<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
  <meta name="theme-color" content="#222">
  <meta name="generator" content="Hexo 4.2.1">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/safari-pinned-tab.svg" color="#222">
  <link rel="stylesheet" href="/css/main.css">
  <link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">
  <link rel="stylesheet" href="/lib/pace/pace-theme-minimal.min.css">
  <script src="/lib/pace/pace.min.js"></script>
  <script id="hexo-configurations">
    var NexT = window.NexT ||
    {};
    var CONFIG = {
      "hostname": "cuiqingcai.com",
      "root": "/",
      "scheme": "Pisces",
      "version": "7.8.0",
      "exturl": false,
      "sidebar":
      {
        "position": "right",
        "width": 360,
        "display": "post",
        "padding": 18,
        "offset": 12,
        "onmobile": false,
        "widgets": [
          {
            "type": "image",
            "name": "阿布云",
            "enable": false,
            "url": "https://www.abuyun.com/http-proxy/introduce.html",
            "src": "https://qiniu.cuiqingcai.com/88au8.jpg",
            "width": "100%"
      },
          {
            "type": "image",
            "name": "天验",
            "enable": true,
            "url": "https://tutorial.lengyue.video/?coupon=12ef4b1a-a3db-11ea-bb37-0242ac130002_cqx_850",
            "src": "https://qiniu.cuiqingcai.com/bco2a.png",
            "width": "100%"
      },
          {
            "type": "image",
            "name": "华为云",
            "enable": false,
            "url": "https://activity.huaweicloud.com/2020_618_promotion/index.html?bpName=5f9f98a29e2c40b780c1793086f29fe2&bindType=1&salesID=wangyubei",
            "src": "https://qiniu.cuiqingcai.com/y42ik.jpg",
            "width": "100%"
      },
          {
            "type": "image",
            "name": "张小鸡",
            "enable": false,
            "url": "http://www.zxiaoji.com/",
            "src": "https://qiniu.cuiqingcai.com/fm72f.png",
            "width": "100%"
      },
          {
            "type": "image",
            "name": "Luminati",
            "src": "https://qiniu.cuiqingcai.com/ikkq9.jpg",
            "url": "https://luminati-china.io/?affiliate=ref_5fbbaaa9647883f5c6f77095",
            "width": "100%",
            "enable": false
      },
          {
            "type": "image",
            "name": "IPIDEA",
            "url": "http://www.ipidea.net/?utm-source=cqc&utm-keyword=?cqc",
            "src": "https://qiniu.cuiqingcai.com/0ywun.png",
            "width": "100%",
            "enable": true
      },
          {
            "type": "tags",
            "name": "标签云",
            "enable": true
      },
          {
            "type": "categories",
            "name": "分类",
            "enable": true
      },
          {
            "type": "friends",
            "name": "友情链接",
            "enable": true
      },
          {
            "type": "hot",
            "name": "猜你喜欢",
            "enable": true
      }]
      },
      "copycode":
      {
        "enable": true,
        "show_result": true,
        "style": "mac"
      },
      "back2top":
      {
        "enable": true,
        "sidebar": false,
        "scrollpercent": true
      },
      "bookmark":
      {
        "enable": false,
        "color": "#222",
        "save": "auto"
      },
      "fancybox": false,
      "mediumzoom": false,
      "lazyload": false,
      "pangu": true,
      "comments":
      {
        "style": "tabs",
        "active": "gitalk",
        "storage": true,
        "lazyload": false,
        "nav": null,
        "activeClass": "gitalk"
      },
      "algolia":
      {
        "hits":
        {
          "per_page": 10
        },
        "labels":
        {
          "input_placeholder": "Search for Posts",
          "hits_empty": "We didn't find any results for the search: ${query}",
          "hits_stats": "${hits} results found in ${time} ms"
        }
      },
      "localsearch":
      {
        "enable": true,
        "trigger": "auto",
        "top_n_per_article": 10,
        "unescape": false,
        "preload": false
      },
      "motion":
      {
        "enable": false,
        "async": false,
        "transition":
        {
          "post_block": "bounceDownIn",
          "post_header": "slideDownIn",
          "post_body": "slideDownIn",
          "coll_header": "slideLeftIn",
          "sidebar": "slideUpIn"
        }
      },
      "path": "search.xml"
    };

  </script>
  <meta name="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
  <meta property="og:type" content="website">
  <meta property="og:title" content="静觅">
  <meta property="og:url" content="https://cuiqingcai.com/page/5/index.html">
  <meta property="og:site_name" content="静觅">
  <meta property="og:description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
  <meta property="og:locale" content="zh_CN">
  <meta property="article:author" content="崔庆才">
  <meta property="article:tag" content="崔庆才">
  <meta property="article:tag" content="静觅">
  <meta property="article:tag" content="PHP">
  <meta property="article:tag" content="Java">
  <meta property="article:tag" content="Python">
  <meta property="article:tag" content="Spider">
  <meta property="article:tag" content="爬虫">
  <meta property="article:tag" content="Web">
  <meta property="article:tag" content="Kubernetes">
  <meta property="article:tag" content="深度学习">
  <meta property="article:tag" content="机器学习">
  <meta property="article:tag" content="数据分析">
  <meta property="article:tag" content="网络">
  <meta property="article:tag" content="IT">
  <meta property="article:tag" content="技术">
  <meta property="article:tag" content="博客">
  <meta name="twitter:card" content="summary">
  <link rel="canonical" href="https://cuiqingcai.com/page/5/">
  <script id="page-configurations">
    // https://hexo.io/docs/variables.html
    CONFIG.page = {
      sidebar: "",
      isHome: true,
      isPost: false,
      lang: 'zh-CN'
    };

  </script>
  <title>静觅丨崔庆才的个人站点</title>
  <meta name="google-site-verification" content="p_bIcnvirkFzG2dYKuNDivKD8-STet5W7D-01woA2fc" />
  <noscript>
    <style>
      .use-motion .brand,
      .use-motion .menu-item,
      .sidebar-inner,
      .use-motion .post-block,
      .use-motion .pagination,
      .use-motion .comments,
      .use-motion .post-header,
      .use-motion .post-body,
      .use-motion .collection-header
      {
        opacity: initial;
      }

      .use-motion .site-title,
      .use-motion .site-subtitle
      {
        opacity: initial;
        top: initial;
      }

      .use-motion .logo-line-before i
      {
        left: initial;
      }

      .use-motion .logo-line-after i
      {
        right: initial;
      }

    </style>
  </noscript>
  <link rel="alternate" href="/atom.xml" title="静觅" type="application/atom+xml">
</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container">
    <div class="headband"></div>
    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner">
        <div class="site-brand-container">
          <div class="site-nav-toggle">
            <div class="toggle" aria-label="切换导航栏">
              <span class="toggle-line toggle-line-first"></span>
              <span class="toggle-line toggle-line-middle"></span>
              <span class="toggle-line toggle-line-last"></span>
            </div>
          </div>
          <div class="site-meta">
            <a href="/" class="brand" rel="start">
              <span class="logo-line-before"><i></i></span>
              <h1 class="site-title">静觅 <span class="site-subtitle"> 崔庆才的个人站点 </span>
              </h1>
              <span class="logo-line-after"><i></i></span>
            </a>
          </div>
          <div class="site-nav-right">
            <div class="toggle popup-trigger">
              <i class="fa fa-search fa-fw fa-lg"></i>
            </div>
          </div>
        </div>
        <nav class="site-nav">
          <ul id="menu" class="main-menu menu">
            <li class="menu-item menu-item-home">
              <a href="/" rel="section">首页</a>
            </li>
            <li class="menu-item menu-item-archives">
              <a href="/archives/" rel="section">文章列表</a>
            </li>
            <li class="menu-item menu-item-tags">
              <a href="/tags/" rel="section">文章标签</a>
            </li>
            <li class="menu-item menu-item-categories">
              <a href="/categories/" rel="section">文章分类</a>
            </li>
            <li class="menu-item menu-item-about">
              <a href="/about/" rel="section">关于博主</a>
            </li>
            <li class="menu-item menu-item-message">
              <a href="/message/" rel="section">给我留言</a>
            </li>
            <li class="menu-item menu-item-search">
              <a role="button" class="popup-trigger">搜索 </a>
            </li>
          </ul>
        </nav>
        <div class="search-pop-overlay">
          <div class="popup search-popup">
            <div class="search-header">
              <span class="search-icon">
                <i class="fa fa-search"></i>
              </span>
              <div class="search-input-container">
                <input autocomplete="off" autocapitalize="off" placeholder="搜索..." spellcheck="false" type="search" class="search-input">
              </div>
              <span class="popup-btn-close">
                <i class="fa fa-times-circle"></i>
              </span>
            </div>
            <div id="search-result">
              <div id="no-result">
                <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
              </div>
            </div>
          </div>
        </div>
      </div>
    </header>
    <div class="back-to-top">
      <i class="fa fa-arrow-up"></i>
      <span>0%</span>
    </div>
    <div class="reading-progress-bar"></div>
    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div class="content index posts-expand">
            <div class="carousel">
              <div id="wowslider-container">
                <div class="ws_images">
                  <ul>
                    <li><a target="_blank" href="https://cuiqingcai.com/5052.html"><img title="Python3网络爬虫开发实战教程" src="https://qiniu.cuiqingcai.com/ipy96.jpg" /></a></li>
                    <li><a target="_blank" href="https://t.lagou.com/fRCBRsRCSN6FA"><img title="52讲轻松搞定网络爬虫" src="https://qiniu.cuiqingcai.com/fqq5e.png" /></a></li>
                    <li><a target="_blank" href="https://brightdata.grsm.io/cuiqingcai"><img title="亮网络解锁器" src="https://qiniu.cuiqingcai.com/6qnb7.png" /></a></li>
                    <li><a target="_blank" href="https://cuiqingcai.com/4320.html"><img title="Python3网络爬虫开发视频教程" src="https://qiniu.cuiqingcai.com/bjrny.jpg" /></a></li>
                    <li><a target="_blank" href="https://cuiqingcai.com/5094.html"><img title="爬虫代理哪家强？十大付费代理详细对比评测出炉！" src="https://qiniu.cuiqingcai.com/nifs6.jpg" /></a></li>
                  </ul>
                </div>
                <div class="ws_thumbs">
                  <div>
                    <a target="_blank" href="#"><img src="https://qiniu.cuiqingcai.com/ipy96.jpg" /></a>
                    <a target="_blank" href="#"><img src="https://qiniu.cuiqingcai.com/fqq5e.png" /></a>
                    <a target="_blank" href="#"><img src="https://qiniu.cuiqingcai.com/6qnb7.png" /></a>
                    <a target="_blank" href="#"><img src="https://qiniu.cuiqingcai.com/bjrny.jpg" /></a>
                    <a target="_blank" href="#"><img src="https://qiniu.cuiqingcai.com/nifs6.jpg" /></a>
                  </div>
                </div>
                <div class="ws_shadow"></div>
              </div>
            </div>
            <link rel="stylesheet" href="/lib/wowslide/slide.css">
            <script src="/lib/wowslide/jquery.min.js"></script>
            <script src="/lib/wowslide/slider.js"></script>
            <script>
              jQuery("#wowslider-container").wowSlider(
              {
                effect: "cube",
                prev: "",
                next: "",
                duration: 20 * 100,
                delay: 20 * 100,
                width: 716,
                height: 297,
                autoPlay: true,
                playPause: true,
                stopOnHover: false,
                loop: false,
                bullets: 0,
                caption: true,
                captionEffect: "slide",
                controls: true,
                onBeforeStep: 0,
                images: 0
              });

            </script>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30020.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 个人随笔 <i class="label-arrow"></i>
                  </a>
                  <a href="/30020.html" class="post-title-link" itemprop="url">篮网输了，但阿杜没输</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>今天早上很早就醒了，激动得睡不着觉，一直期待着篮网和雄鹿的抢七大战。</p>
                  <p>总体上看，其实雄鹿整体纸面实力还是占优一些，但是篮网有我杜，我始终相信有我杜什么奇迹都会发生。再加上篮网主场，还有一些历史数据，比如雄鹿客场抢七没赢过，还有裁判吹罚对主场有利，还有腾讯女主播不是美娜…反正种种的一切似乎还是偏向篮网的。</p>
                  <p>比赛开始，第一节我其实就求篮网不挖坑就行了，因为之前几场都是开局先挖一个大坑，然后后面就很难填了，不过好在第一节僵持住了。</p>
                  <p>第二节和第三节就不说了，反正挺焦灼的，我和我的好朋友，也是阿杜球迷，一直线上交流着，进球我们就庆祝，不进就互相安慰下。</p>
                  <p>一直到第四节吧，还剩三四分钟那会还是领先的，但是后来一两分钟居然被反超了，最后不到一分钟，落后四分，那会我俩都觉得要凉凉了。</p>
                  <p>但是阿杜站出来了，最后雄鹿罚球完就剩两分分差。</p>
                  <p>那会是 109:107，篮网落后 2 分，绝杀 or 加时 or 回家，生死就在一瞬间！！！</p>
                  <p>那会我真的是感觉心脏都要跳出来了，疯狂刷着文字直播和实时比分，因为文字直播和实时比分比视频快一些。</p>
                  <p>我简直那几秒激动得快不行了，真的很难想象阿杜在场上是什么心情。</p>
                  <p>但！我那会刷到了文字直播，突然比分变成了 109:110，我知道进三分了！！！</p>
                  <p>我那会真的太激动了，绝杀了！！！真的很难以想象那会我是多么欣喜！！！</p>
                  <p>然后马上视频直播就来了，看着阿杜最后在最后几秒，运球，转身，三分！进了！！！</p>
                  <p>我那会看到就直接超大声喊出来了！！！太激动了！！！</p>
                  <p>太牛逼了，阿杜就是永远的神！</p>
                  <p>然而，看了看回放，阿杜踩线了，是 2 分，最后变成了 109 平，最后进了加时。</p>
                  <p>也可以吧，还有机会的。</p>
                  <p>加时一上来篮网就领先了 2 分，后来好几分钟双方都没得分，最后就剩一分钟多一点了吧，篮网还领先 2 分，我觉得是不是稳了。</p>
                  <p>后来雄鹿字母哥打进追平。</p>
                  <p>我记得就在这时候，下一个回合让我特别失望，阿杜面临严防没进，但是有前场板，给了空位的哈里斯。我这时候心想，体现你价值的时候到了，哈里斯，你得进啊！！！然而，伴随着打铁声，还是没进…</p>
                  <p>哈里斯你就不能争口气吗？？？</p>
                  <p>113:111 了，篮网最后时刻又落后了 2 分，我的心一下子又揪了起来。</p>
                  <p>最后几秒钟，最后的时刻，篮网落后两分，哈登把球给阿杜，霍勒迪防得挺好的，但阿杜最后没有再完成绝杀了。球挺正的，但是短了，是真的累了。</p>
                  <p>我记得阿杜投出的那一刻，眼中充满了期待，但可惜没进，他的眼神又转为了失落和无力，太可惜了。</p>
                  <p>就这么结束了吗？这么关键的时刻就以这种方式告终了吗？</p>
                  <p>我就心想，最后还有暂停的吧，教练你都不叫个暂停跑个战术的吗？就算你没啥战术，最后叫个暂停让阿杜休息休息也行啊，搞不懂纳什什么蜜汁操作。</p>
                  <p>但也没办法吧，球员毕竟也是可以叫暂停的，阿杜应该就是想自己干，最后一个球没有进就是没有进了。</p>
                  <p>输了，认了。</p>
                  <p>关于阿杜，毋庸置疑，联盟第一人无需辩驳。阿杜打满全场 53 分钟，48 分，全场一秒钟都没有歇，可谓是倾尽所有，无数次挽救球队于危难之中，阿杜真的是尽力了。尤其第四节最后的绝平，真的太牛逼了！yyds！</p>
                  <p>关于哈登，哈登也是尽力了吧，我对哈登没有什么怨言，他也是有伤在身，打满全场，虽然说表现不佳，因为没有恢复最佳状态，全场三分也不准也没有多少突破杀伤，但哈登G5 坚持带伤复出，已经连续带伤打了三场了，还是致敬。</p>
                  <p>关于纳什，我不想多说了，太多太多让我吐槽的了。就说今天最后时刻，即使球员没叫暂停，你叫个暂停布置下战术不行吗？叫个暂停让阿杜休息下不行吗？另外不怪你季后赛全场死用主力，因为毕竟球员也想上场拼尽全力，但是关键时刻，我真的没看出来纳什你有啥战术啊？另外季后赛死用主力没啥，常规赛你还让阿杜每场打那么久，甚至都能上好多次 40 分钟，至于吗？还有，格林今天就打了几分钟，哈里斯这么拉垮你换格林试试不行吗，天王山不记得是谁打出来的了吗？还有我一直很迷惑的，阿利泽约翰逊，常规赛也是拿 20 + 20 的，就这么被你彻底雪藏了？</p>
                  <p>关于哈里斯，算了，没得说了，关键时刻就是挺不起来的，萎了一个系列赛了，交易走吧。</p>
                  <p>关于格里芬，很硬，非常硬，防字母防得很好了，进攻也很不错，打出远超薪资的身价，我估计下赛季肯定不会这么低工资了，蔡老板高薪也得拿下啊。</p>
                  <p>关于布朗，我觉得还挺不错的，很有活力，尤其本场比赛的几个前场板，非常给力。</p>
                  <p>关于小乔丹，哦，这么久不见我已经不认识你了。</p>
                  <p>关于字母哥，那一垫脚欧文一直让我耿耿于怀，小脚一挪？阿德托昆博？就冲你这一脚，太脏了！我不会祝福你的，最后总冠军只要不是雄鹿，都好。希望 76 人晋级，让大帝好好教训下字母哥。</p>
                  <p>最后再说回阿杜吧，我支持阿杜十多年了，每次有阿杜的球我也是密切关注，赢了开心一整天，输了可能难过一整天，今天就这么遗憾输了，挺难过的，挺惋惜的，最后功亏一篑。但不管怎样，阿杜整个赛季带给我的惊喜已经远超我预期了，赛季开始前我很担心阿杜跟腱大伤之后状态大不如前，但到如今，一次次的超神表现带给了我太多的惊喜，身体条件看着也很不错，似乎跟腱伤势的隐患已经非常小了。最后这个系列赛，天王山之战、这场比赛，真的你已经完全倾尽全力，不能要求你更多了，真的，太强了。你用自己的实力让各路的黑子闭上了嘴，用自己一次次投篮证明了自己就是妥妥的联盟第一人。虽然输了，但是你这个赛季带给大家的惊喜，你收获的尊重和认可，我想也是你非常想得到的东西，也为此为你感到高兴。篮网输了，但你没输。</p>
                  <p>哦对了，再补一句，篮球的比赛，还是得看直播而不是回放，因为只有直播，一切结果是未知的，才能有无限的期待，才能有无限的代入感，才能在这个过程中感受进球霎那间的极致情绪的绽放！就像本场第四节阿杜的绝平球，进球一瞬间肾上腺素飙升到极致的感觉，这或许是篮球带给我的澎湃激情！如果是录播，一切都知道的结果，那是不会有这种感觉的。另外也很感谢和我一起看球的朋友，一同分享喜悦，一起分享感动，真的难能可贵。</p>
                  <p>阿杜的赛季结束了，我这个赛季也不看球了，腾讯体育也卸载了。</p>
                  <p>下赛季卷土重来，哥三人健健康康地，继续向前进。</p>
                  <p>还是那五个字——篮网总冠军！</p>
                  <p>更多精彩内容，请关注我的公众号「进击的 Coder」和「崔庆才丨静觅」。</p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-06-20 12:41:06" itemprop="dateCreated datePublished" datetime="2021-06-20T12:41:06+08:00">2021-06-20</time>
                </span>
                <span id="/30020.html" class="post-meta-item leancloud_visitors" data-flag-title="篮网输了，但阿杜没输" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>2.5k</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>2 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30019.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 个人随笔 <i class="label-arrow"></i>
                  </a>
                  <a href="/30019.html" class="post-title-link" itemprop="url">公众号运营的一些思考</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>运营公众号已经两年多时间了，之前时间还好，原创不少，大家也都挺愿意看的。但最近我观察发现，我的公众号「进击的 Coder」呈现出几个不健康的状态：</p>
                  <ul>
                    <li>
                      <p>总体阅读下滑</p>
                    </li>
                    <li>
                      <p>粉丝粘性下滑</p>
                    </li>
                    <li>
                      <p>粉丝数量下滑</p>
                    </li>
                  </ul>
                  <p>其实根本原因还是原创变少了，当然还有其他的影响因素一起导致了这样的情况。</p>
                  <p>原创是公众号的至关重要的一部分，是公众号的血液，没有原创内容的文章是很难脱颖而出的，粉丝关注关注的其实就是能从中获取一些独到的价值。</p>
                  <p>但由于最近一段时间原创文章确实少，都在转载一些文章，和其他技术公众号大同小异，都是转来转去的，久而久之，读者就觉得没什么意思，取关什么的那就是自然而然的了。</p>
                  <p>那为什么原创变少了呢？总结下来有这么几点原因：</p>
                  <ul>
                    <li>
                      <p>我工作比较忙，现在处于项目的关键阶段，项目周期比较赶，确实写原创文章的时间变少了。</p>
                    </li>
                    <li>
                      <p>由于最近半年和一年写的文章都是爬虫书的一部分，所以不好提前发出来，所以这就导致了公众号的原创文章变得很少。</p>
                    </li>
                    <li>
                      <p>最近我也开了一个新的公众号「崔庆才丨静觅」，当时就是想在这个小号上简单记录自己的一些想法的，所以在这个小号上写了一些原创，但由于我当时太基于追求小号的质量和增长了，所以不论是技术文章还是个人感悟都发到小号上，「进击的 Coder」就直接转载这个小号上的文章，所以一些原创被分流了。</p>
                    </li>
                  </ul>
                  <p>当然除了原创变少，还有几个导致目前不健康状态的原因：</p>
                  <ul>
                    <li>
                      <p>由于最近我大多为转载的文章，所以读者的一些留言询问一些问题我可能不了解细节，那就可能回答比较浅或者干脆放出来不予回答，跟读者的互动越来越少。</p>
                    </li>
                    <li>
                      <p>公众号生态的变化，公众号生态早已一片红海，越来越多的创作者都加入公众号，都在竞争流量，转载和广告大量出现，导致读者现在对公众号的打开率越来越低，不论是单个还是总体。</p>
                    </li>
                    <li>
                      <p>微信公号本身的推荐算法应该也有一定的作用，比如原创文章的权重相比之前我感觉更高了，反而转载过多的文章权重比例进一步下滑。</p>
                    </li>
                  </ul>
                  <p>嗯，基本上就是这样的现状，导致了公号出现了不健康的状态。</p>
                  <p>经过一些思考和跟小伙伴的讨论，我们得到了一些思考，决定后面转变一下运营思路，大致总结下：</p>
                  <ul>
                    <li>
                      <p>依然坚持原创是根本，唯有原创才是公众号经久不衰的秘诀，所以以后会继续坚持原创，当然由于本人时间原因，每周每个号 1-2 篇应该算是一个小目标，也就是两个号「进击的Coder」和「崔庆才丨静觅」两个号每周会发 2-4 篇原创文章。</p>
                    </li>
                    <li>
                      <p>关于原创我们也在联系一些渠道，比如如果大家有不错的原创文章，也欢迎前来本公众号投稿。</p>
                    </li>
                    <li>
                      <p>之前为了每天都发文章，可能着急忙慌地找几篇就转了，质量并不高，最后导致阅读也不好，给读者提供的价值也不够，所以调整了一下策略——非必要不发文。也就是说，如果今天确实没有什么好发的，那就不要制造信息垃圾了。要发就发一些有价值的，高质量的，所以会更加严格控制公号的文章质量。</p>
                    </li>
                    <li>
                      <p>区分好「进击的 Coder」和「崔庆才丨静觅」两个号的定位，之前我对两个公号的定位并不清晰，甚至有一段时间不论技术文章还是个人感悟都发到「崔庆才丨静觅」上面，「进击的 Coder」一直是转载文章，这样会导致「进击的 Coder」出现上述我说的不健康的状态。所以后面，「进击的 Coder」会侧重于发技术文章，也就是说我平时写的有关技术的所有文章都会放到这个号上面来，包括网络爬虫、技术总结、工具推荐、Web、AI、小知识点等等。「崔庆才丨静觅」更加私人一点，就会发我日常的一些感悟，比如我的工作感想、我的生活状态、我的碎碎念、我的读书笔记等等。如果大家感兴趣的话可以关注下。</p>
                    </li>
                    <li>
                      <p>增加和读者的互动，之前的一些留言，跟读者的互动性不好，后面会注意多增加一些互动和交流，增加读者粘性。</p>
                    </li>
                    <li>
                      <p>不定期搞一点小互动，比如送一些小礼品、书等等。</p>
                    </li>
                  </ul>
                  <blockquote>
                    <p>PS：当然毫不避讳地说，由于我也需要公号来获取一些收入，所以有时候公号也会接一些广告的，但是我也会控制好广告的频率和质量，广告也都是一些技术课程类的，大家如果感兴趣希望如果也可以支持下，感激不尽！</p>
                  </blockquote>
                  <p>就是这样啦，如果大家还想到什么好的点子也欢迎告诉我哈。我还是非常希望我能够通过两个公众号为大家提供更好的内容和价值的。</p>
                  <p>Fighting！</p>
                  <p>更多精彩内容，请关注我的公众号「进击的 Coder」和「崔庆才丨静觅」。</p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-06-19 15:41:06" itemprop="dateCreated datePublished" datetime="2021-06-19T15:41:06+08:00">2021-06-19</time>
                </span>
                <span id="/30019.html" class="post-meta-item leancloud_visitors" data-flag-title="公众号运营的一些思考" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>1.7k</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>2 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30015.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 个人记录 <i class="label-arrow"></i>
                  </a>
                  <a href="/30015.html" class="post-title-link" itemprop="url">火车上遇见的一件小事</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>这件事是前几天发生的，端午假期我出去参加同学婚礼，假期最后一天我坐高铁回北京。</p>
                  <p>高铁上，一个小男孩子在说话比较大声，而且看起来比较调皮，敲了小桌板几下，发出了一些声响。然后他爸爸就很生气，应该是呵斥了他几句，然后那个孩子就哭了起来。</p>
                  <p>其实哭得还挺大声的，一直哭了好几分钟，如果一般情况下，听到孩子哭其实是很让人心烦的，但是这次发生的事情让我唯一的感觉却是替孩子感到惋惜和同情。</p>
                  <p>那个孩子中间说了好几次：“爸爸，是我做的不对吗？”</p>
                  <p>爸爸一开始没搭理，孩子问了好几次之后，他爸爸就回答：“别说话，你看别人都不说话，你也不要说话啊。”</p>
                  <p>孩子应该是听到并不是自己想要的答案，然后就接着问：“爸爸，是我做的让你感到失望了吗？”</p>
                  <p>爸爸还是那句话：“别说话，安静一点。”</p>
                  <p>然后孩子还在继续问：“爸爸，我不想让你生气和失望，爸爸是我那里做的不对呢？”</p>
                  <p>爸爸依然还在说：“别说话，你看别人都不说话，你也不要说话。”</p>
                  <p>卧槽，听到这里我真的感觉这爸爸怎么这样啊！</p>
                  <p>后面反复了几句，爸爸依然就是那个回复，后来孩子也不再问了，也就不说话了，火车上又安静了起来。</p>
                  <p>但我内心还是久久不能平静，直到现在想起来真的想说孩子爸爸几句，真的我感觉这件事让我真的很同情这个孩子，而且对爸爸这种态度感到非常的愤怒，怎么能这么培养和教育孩子呢？</p>
                  <p>孩子在成长的过程中，尤其在这个阶段，他对整个世界没有很好的认知，不知道自己做的事情是不是对的，而且对世界充满了好奇，所以他遇到自己不明白的事情的时候，非常迫切需要得到一个答案和反馈，如果这时候家长可以给予好的引导，对孩子的成长简直太重要了。</p>
                  <p>而且更让我感到惋惜的是，这个孩子真的算很懂事了，他已经可以说出“爸爸，是我做的让你感到失望了吗？我不想让你生气和失望。”这样的话了，孩子都能表达自己的感受和想法，这真的已经非常好了。</p>
                  <p>但是他爸爸的回答简直太让人失望和生气了，他非但没有正面回答孩子的所有问题，而且一直在命令孩子不要讲话，完全没有一点正向的反馈，跟孩子好好说说不好吗？</p>
                  <p>比如就说，宝贝我没有生气和失望，就是刚才的你声音比较大，会影响到其他的乘客，我们要做一个好的孩子，在火车上不要大声讲话以免影响他人，以后我们火车上安静一些，这样就更好了。首先能够正面回答孩子的疑问，然后通过一些正向的激励来帮助孩子了解一些知识和让他认识到应该做的事情，这样不好吗？这孩子听了之后，一方面就知道自己做的是不是对的，应该怎么做才能更好，因为这个孩子本身已经很懂事了，他也想成为一个好的孩子，知道了哪些是对的，我相信这个孩子后面会注意的。而且经过这些事，孩子也能明白一些道理，这是从生活中学到的，对孩子特别重要。</p>
                  <p>虽然我没有孩子啊，但站一个旁观者的角度，真的觉得家长应该提供一个更好的引导和教育，这样孩子才能更好地成长。</p>
                  <p>更多精彩内容，请关注我的公众号「进击的 Coder」和「崔庆才丨静觅」。</p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-06-18 09:10:33" itemprop="dateCreated datePublished" datetime="2021-06-18T09:10:33+08:00">2021-06-18</time>
                </span>
                <span id="/30015.html" class="post-meta-item leancloud_visitors" data-flag-title="火车上遇见的一件小事" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>1.2k</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>1 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30014.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 个人记录 <i class="label-arrow"></i>
                  </a>
                  <a href="/30014.html" class="post-title-link" itemprop="url">见证了死神杜兰特最牛逼的一场比赛</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>今天比较忙，等到写这篇文章的时候已经第二天了，但是还是不得不写写，因为杜兰特这场天王山之战的表现是在是太牛逼了！</p>
                  <p>我平时是看 NBA 的，是杜兰特的死忠粉，喜欢杜兰特有十年了，从高中的时候经常听到同学议论 NBA，说雷霆队有个叫杜兰特的很厉害，跟着看了几场球，后来就成了杜兰特的球迷。</p>
                  <p>我也习惯称杜兰特为阿杜、KD，所以后面文章我就叫阿杜了，感觉比较亲切。</p>
                  <p>当然现在我也是毫无疑问的的篮网球迷，因为阿杜去哪个球队我就支持哪个球队。从雷霆到勇士到篮网，他也经历过低谷、经历过高光，勇士的两连冠真的发自内心为他感到高兴，但前年他遭遇了跟腱断裂大伤，我也一直在关注各种消息期盼他能王者归来。</p>
                  <p>这个赛季，终于盼来了阿杜的复出，我特别希望他能回到当时巅峰的状态，希望跟腱的伤势对他的影响尽量是最小的，但也免不了的每场比赛都会担心他的跟腱伤势会不会复发。尤其是到了现在的季后赛，对抗强度上升，更是每场都在祈祷阿杜不要受伤。</p>
                  <p>幸运的是，这个赛季没有再看到阿杜的跟腱伤势有任何复发迹象，当然他也在尽力保护自己，比如落地的时候会用摔倒的方式缓冲一下力量。每多看一场，我对阿杜跟腱的恢复情况就会越乐观一些，应该算是彻底好了吧，谢天谢地。</p>
                  <p>扯远了，今天我来就是专门来说说今天阿杜的超神表现的。</p>
                  <p>可以说，今天的表现，任何华丽的词藻都不足以表达阿杜的牛逼了，简直就是天神下凡！打满全场 48 分钟，一分钟都没有休息，23 投 16 中，砍下 49 分 + 17 篮板 + 10 助攻的超级三双，外加 3 抢断 2 盖帽，率领篮网在一度落后 17 分的情况下、在两大巨星队友都遭遇伤病的情况下、在众多队友都失准的情况下，带领球队完成惊天大翻盘赢下雄鹿，最后一节真的是把我都看哭了，太悲壮了！</p>
                  <p>关注这场比赛的朋友都知道这场比赛对阿杜来说意味着什么，本来篮网的形势一片大好，但是和雄鹿的系列赛第一场哈登就因为腿筋伤势退场，第四场欧文又被字母歌垫脚无法出战。虽然说哈登今天出战了，但是状态远不及正常水准。上半场一开场就大比分落后，这时候靠的就只有阿杜了。最后的结果大家也都知道了，阿杜天神下凡般的表现把这场比赛硬生生拿下了！把字母哥彻底打服了，把众多对阿杜一直持怀疑态度的群众打服了，把国内第一杜黑徐静雨打服了。我愿称这场比赛就是阿杜彻底的封神之战，是迄今为止阿杜职业生涯最牛逼的一场比赛，没有之一。</p>
                  <p>先说说徐静雨吧，他是网上一个比较知名的说球的。客观来讲，他确实对一些比赛或者球员的分析有自己的独到见解，这方面我是认可他的。他是库里球迷，一说到库里那就可劲吹，但经过观察，我发现他是阿杜的黑粉，可能是因为阿杜抢了库里两个 FMVP 的原因吧，一直耿耿于怀，然后一个劲说 MVP 比 FMVP 含金量大多了，反正就是库里有的就可劲吹，没有的就可劲贬。一听到他说阿杜不好的我就来气，甚至连 CJ 单换阿杜的话都说出来，就觉得他真是一个无脑黑子，中间我还把他拉黑了一段时间。但最近发现，徐静雨的口风发生了变化，一方面的原因可能是库里没有进季后赛，另一方面却是也是阿杜打出的表现的确让人心服口服，身体条件也观察到愈发硬朗，攻防两端的表现的确是非常超群。今天我专门去看了徐静雨怎么说，一进去就看到几个大字「全力杜已超全力詹」，好家伙，这是彻底被阿杜打服了，视频中他也对阿杜各种赞誉，被阿杜的表现深深折服，甚至都已经说全力杜已经超过 12 年全力詹这样的话了，全网第一杜黑被打服了。</p>
                  <p>然后说说我心里的感受吧，其实徐静雨说的一番话我也是认同的，就是阿杜需要一个契机来证明自己的超群价值。这时候有人可能就说了，阿杜的能力还需要证明吗？其实在我看来，需要的。</p>
                  <ul>
                    <li>
                      <p>首先在雷霆时期，阿杜的表现足够牛逼了，尤其 13-14 赛季已经证明了自己单核带队的能力，并勇夺得常规赛 MVP，但这毕竟是常规赛。</p>
                    </li>
                    <li>
                      <p>在雷霆最后一个赛季，阿杜在跟勇士的鏖战中最后被翻盘，最后阿杜就加入了勇士，这也成了阿杜一生中的一个巨大的黑点，网上一众黑子各种骂。当然我不认为这是黑点哈，我觉得阿杜去到更好的地方，先实现自己的冠军梦就好，他做的决定我是完全支持的。</p>
                    </li>
                    <li>
                      <p>阿杜在勇士夺得了两个冠军，但是在很多人看来，这两个冠军似乎都太简单了，毕竟勇士这个球队本身就太强大了，银河战舰级别的配置，所以外界都觉得这两个冠军没有什么含金量，也在质疑阿杜要是单核带队是不行的。</p>
                    </li>
                    <li>
                      <p>阿杜的内心是很敏感的，他也很在意外界对自己的看法，想要赢得外界的尊重。所以他离开勇士的一个原因就有想再证明自己的价值。</p>
                    </li>
                    <li>
                      <p>篮网今年阵容经过一番操作机会变得非常豪华了，阿杜、哈登、欧文，篮网整个阵容可以说都能比得上 17-19 赛季的勇士了，阿杜伤停一段时间，哈登又带队打出逆天表现，于是又有人开始质疑阿杜的带队能力，说阿杜单核带队不行，只能作为一个强力终结点，不能很好地带动队友。</p>
                    </li>
                  </ul>
                  <p>综合以上几点，加上现在特殊的情况，三巨头除了阿杜其他两个都伤了，而且篮网刚刚经历了从 2-0 到 2-2 点局面，被雄鹿连扳两盘，而且上一场欧文刚刚伤了，不论是阵容上还是士气上，篮网都处于很大的劣势。而天王山之战的重要性不言而喻，此时篮网能依靠的就只有阿杜了。</p>
                  <p>所以如果这一场，阿杜能够爆发并带领球队获胜，就是对自己非常非常好的证明，这是天时造就的机会，证明自己的时候到了！</p>
                  <p>不负众望，阿杜天神下凡般的表现大家也看到了，不管是进攻终结还是防守盖帽，攻防两端打出来了统治级表现。另外阿杜不仅仅作为一个终结点，还送出了 10 次助攻，不光得分还能串联球队，就是以往的阿杜和哈登的超强结合体，攻防、串联，所有的所有都做到淋漓尽致。另外阿杜对胜利的渴望也是到了极致，打满了全场 48 分钟，一个个无解中投，一次次突破上篮，还有最后的压哨三分，死神镰刀挥舞起来，彻彻底底的统治级表现，这就是一场封神之战，打破所有的质疑，赢得了足够的尊重。所以这也是我愿意把他称之为阿杜生涯最牛逼的比赛，没有之一。</p>
                  <p>最后，希望篮网全员能够恢复健康，继续向前征战。</p>
                  <p>篮网总冠军！阿杜 FMVP！</p>
                  <p>更多精彩内容，请关注我的公众号「进击的 Coder」和「崔庆才丨静觅」。</p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-06-17 01:26:24" itemprop="dateCreated datePublished" datetime="2021-06-17T01:26:24+08:00">2021-06-17</time>
                </span>
                <span id="/30014.html" class="post-meta-item leancloud_visitors" data-flag-title="见证了死神杜兰特最牛逼的一场比赛" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>2.4k</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>2 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30013.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 技术杂谈 <i class="label-arrow"></i>
                  </a>
                  <a href="/30013.html" class="post-title-link" itemprop="url">分享一个不错的笔记软件</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>大家知道我平时会写一些文章，有的朋友也会经常问我：你是用的什么软件写作的？用什么软件管理这些文章的？</p>
                  <p>我之前其实有介绍过我正在使用的支持跨平台写作的解决方案，是基于苹果的 iCloud Drive 来实现的。</p>
                  <p>首先我是非常喜欢用 Markdown 来写内容的。在电脑上，我可以用文本编辑器 Typora，工作空间都是在 iCloud Drive 上，写完之后就会自动同步，然后我在手机上是用了另外一款软件叫做 Blockquote，也能直接打开 iCloud Drive 的文件，手机上也可以编辑 Markdown 文件。</p>
                  <p>手机上的软件类似这样子：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/1624269196383.png" alt=""></p>
                  <p>但是呢，说实话手机上的这款软件我觉得并没有那么好用，但主要因为他能直接打开原生的md文件，而且没有那么花里胡哨的功能，所以当时就选它了。</p>
                  <p>但这几天由于我出门了，不方便带电脑，所以有时候就想用手机来写，平时我大多数都是用电脑比较多，这次改成手机直接用 Blockquote 还觉得有些不习惯，逐渐感到有些乏力。</p>
                  <p>于是就想着看看有没有更好用的替代品。</p>
                  <h2 id="基本需求"><a href="#基本需求" class="headerlink" title="基本需求"></a>基本需求</h2>
                  <p>我先说一下我的基本的需求：</p>
                  <ul>
                    <li>
                      <p>第一点呢就是我必须要做到跨平台的同步，因为我有好多台设备，在不同的时间在不同的设备上工作，比如上班时间在公司的 iMac 上，下班了在家里的 iMac 上，周末又会带着 Macbook Pro 出去，路上又在用 iPhone，偶尔还会用用 iPad。在这个过程中我想要随时随地把一些东西记录下来，所以我想要实现无缝的协作切换和高效率的实时同步。所以，我的所有的文本和笔记都必须要是跨平台协同同步的，这个是一个最基本的要求。由于我使用的是苹果全家桶，所以说我之前基于 iCloud Drive 就可以很轻松的实现这所有的功能，然后不同平台上用不同的编辑器来编辑就行了。</p>
                    </li>
                    <li>
                      <p>第二点我想要保留原生态，即文本的平台无关性。我想编辑的内容是实实在在存在的一个 md 后缀的纯文本文件，好多 md 文件就放在一个文件夹下，也有对应的放图片的文件夹，以便于我随时随地能够把一个 md 文件分享出去或者切到另外的软件打开，甚至加到 Git 中保存起来。比如说我之前调研过「熊掌记」，它对 Markdown 支持挺好的，但是当我想获取原始的 Markdown 文件树的时候，发现「熊掌记」已经把它做到平台里面了，我是很难获取整个的 md 文件夹的，所以我就没法用 Git 来管理我所有的 md 文件了。</p>
                    </li>
                  </ul>
                  <p>基于这两点，之前的方案是能实现的，但是手机上的 Markdown 编辑软件我实在觉得乏力。</p>
                  <p>所以我也在反思，为什么我一定要执着于原生的 md 文件的编辑呢？我思考了一下，我真正想要的就是第一点——跨平台的同步，是不是我在编辑一个真实的 md 文件不重要，如果我用的平台能够支持导入 md，支持导出 md，那不就好了吗？甚至版本控制我也不用做了，如果一个笔记软件能支持版本控制那我直接用不就好了吗？想到这里，觉得之前似乎走到坑里去了，现在其实很多的厂商都已经提供了这样的解决方案，比如说印象笔记、有道云笔记、还有 Notion 等等。各种各样的笔记软件，其实都已经做到全平台的支持和跨平台的同步了。</p>
                  <h2 id="Notion"><a href="#Notion" class="headerlink" title="Notion"></a>Notion</h2>
                  <p>经过一番勘查，我找到了 Notion。经过这么几年的发展，Notion 的功能也变得越来越强大了。而且它对 Markdown 也有一定的支持，虽然说它的语法并不是完完全全的 Markdown，但一些特色功能的确很能打动人心。</p>
                  <p>首先 Notion 的设计思路就挺好的 —— 万物皆是 Block，即一个块。比如一段文本、一张图片、一个视频、一段代码，只不过 Block 有自己的类型，每个 Block 就像一个个小组件，最终组合成了一篇文章。有了 Block 的设计，一些实现上的灵活性就更高了。要添加新的功能只需要加新的 Block 就好了。</p>
                  <p>另外 Notion 的功能还是很强的，因为 Block 的加持，所以文档不仅仅可以是文档，又可以是一个项目管理图、一个课程表、一个思维导图、一个计划表等等，All in One！</p>
                  <p>但不能光说好啊，对于不好的地方，我也进行了一番查阅，Notion 有什么不好的呢？其中很多人反馈的就是它的服务器在国外，所以说一些加载延迟比较高，网络同步效率一般。另外一个反馈就是 Notion 对于中文的支持不好，现在我看到 Notion 只支持了韩文还有英文，然后据小道消息，中文的支持。还在计划和测试中，但是不确定什么时候正式上线。还有就是 Notion 因为是一款国际化软件，所以对国内生态支持不好，比如微信登录、国内手机号登录等等。</p>
                  <p>反正这些问题还是蛮受诟病的。</p>
                  <h2 id="遇见-wolai"><a href="#遇见-wolai" class="headerlink" title="遇见 wolai"></a>遇见 wolai</h2>
                  <p>然后找着找着，我就又发现了另外一款软件。叫做我来 wolai，就基本上是一个国内版的 Notion。</p>
                  <p>wolai 这名字的确有点奇怪啊，但这影响不大，重要的还是功能。</p>
                  <p>我一开始对这个软件其实还是持有怀疑态度的，因为我总觉得国内的一些公司可能作为刚初创的公司，它的这个质量的把控可能并不是很好，或者是说服务不稳定。另外可能用着用着这个公司就跑路了，倒闭了，这也是有可能的。</p>
                  <p>但怎么说呢？我个人试用了一下这一款软件，整个我觉得还是挺符合我的需求的。虽然说它是对标了国外的 Notion 所有的一些功能键。和 Notion 非常的相似。但我觉得只要做到好这个软件好用。能够满足我的需求。那他不妨成为我的一个候选。</p>
                  <p>我还专门去查了一下这个公司的创始人以及他们做事情的一些态度理念。</p>
                  <p>看了之后，发现 wolai 其实才上线了一年的时间，但功能已经相对完善了，我觉得现在的功能点做的还算不错了。</p>
                  <p>wolai 的创始人叫马锐拉，知乎主页是：<a href="https://www.zhihu.com/people/marila" target="_blank" rel="noopener">https://www.zhihu.com/people/marila</a>。</p>
                  <p>他们做 wolai 的初衷是这样说的：</p>
                  <blockquote>
                    <p>最初开始做 wolai ，出于一个非常简单的原因——作为一个管理者，面对当时公司中几十个互相割裂的内部系统、平台，我往往需要通过拼凑信息碎片并手动构建关联，才能完成信息的追溯与重组。循环往复、极为低效地搜寻信息需要耗费巨大的心力，更别说一群人通过这样的方式来进行协作，可想而知是多么痛苦。而一些相对简单的部门内部协作流程，和协作本身，也没有很好地系统可以承载、实现，最后都变成一个个微信群。每个人都要在忍受无数“信息噪音”的同时，随时留意与自己真正相关的聊天内容。我们都被绑架在工作群聊中。凡此种种，让我觉得信息必然有更好的组织方式，大量日常协作流程也不应该依赖于在群聊中共享信息流。我开始意识到，我们缺少一个真正解决这些问题的工具。</p>
                  </blockquote>
                  <p>他们对 wolai 的定位是这样的：</p>
                  <ol>
                    <li>
                      <p>可以更好地组织信息，不论是组织方式还是交互体验；</p>
                    </li>
                    <li>
                      <p>可以让每个人都能自由构建流程与应用，满足团队日常工作所需；</p>
                    </li>
                    <li>
                      <p>可以进行更好的分享与协作；</p>
                    </li>
                    <li>
                      <p>不能是一个呆板严肃的被老板逼着用的办公软件；</p>
                    </li>
                    <li>
                      <p>团队或企业可以完成日常 80% 以上的协作，让 Office 回归专业软件，让微信回归即时通讯……</p>
                    </li>
                  </ol>
                  <p>到今天为止，已经累计发布了将近 900 个版本，平均一天发布近 3 次，优化、迭代、完善了无数产品功能；也有了 Windows 、Mac 、Linux 、iOS 、Android 全平台客户端；建立了云服务的空间计划体系，夯实了云端协作平台的基础……终于也算变成了一个有模有样的产品。</p>
                  <p>卧槽，牛逼，能一年搞得这样，真的很佩服了，尤其还支持 Linux！</p>
                  <p><img src="https://qiniu.cuiqingcai.com/1624269221814.png" alt=""></p>
                  <p>而且这个界面设计感，我觉得很不错！</p>
                  <p>其实我本来想好好介绍一下这个软件的，但是我感觉我自己写了之后，和原来官方写的文章其实也大差不差。而且我感觉人家的这篇文章写的也挺好的。</p>
                  <p>所以大家可以直接来看看原介绍文章吧：<a href="https://zhuanlan.zhihu.com/p/379723832" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/379723832</a>。</p>
                  <h2 id="功能"><a href="#功能" class="headerlink" title="功能"></a>功能</h2>
                  <p>我就简单说几个让我觉得眼前一亮的功能吧。</p>
                  <h3 id="界面"><a href="#界面" class="headerlink" title="界面"></a>界面</h3>
                  <p>大家可以发现，我每次介绍软件都要先评论一下界面，就简单放个官方的图吧：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/1624269249335.png" alt=""></p>
                  <p>文章支持 Markdown 绝大多数语法，而且文章上面可以放头图，而且还有专门的 icon，五颜六色的 tag 支持，整个风格是 Material 风格设计，一些边距、图标让人感觉很舒服。</p>
                  <p>他们自己也说了：</p>
                  <blockquote>
                    <p>在调性上，区别于千篇一律使用蓝色为主色调的企业应用，我们反其道而行，以暖色为主色调。去除矩形的锋利棱角，用圆润的边角体现 wolai “专业却不失温度”的企业文化和产品理念。</p>
                  </blockquote>
                  <p><img src="https://qiniu.cuiqingcai.com/1624269267357.png" alt=""></p>
                  <p>一些文章可以灵活分类组织，每个分类还有单独的图标，井然有序，给单调的列表增加了几分活力有木有！</p>
                  <p>我爱了。</p>
                  <p>看看我这篇文章就用 wolai 写的，就看这个图标设计吧，左上角可以选一个图标，支持 Emoji，各种颜色的扁平图标，甚至是动态日历，比如这就是个动态日历：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/1624269282495.png" alt=""></p>
                  <p>同时设置完了之后还能显示在文章标题前面，这细节到位了！</p>
                  <h3 id="全平台同步"><a href="#全平台同步" class="headerlink" title="全平台同步"></a>全平台同步</h3>
                  <p>另外很重要的当然就是这个全平台的同步了，我看了一下，它支持 Mac、Windows、Android、iPad、iPhone 各种各样的平台，尤其还支持 Linux！这个一上来就把这个好感度拉满了。</p>
                  <p>而且 Mac 也专门为 M1 芯片做了适配。</p>
                  <p>很妙！</p>
                  <h3 id="导入导出"><a href="#导入导出" class="headerlink" title="导入导出"></a>导入导出</h3>
                  <p>另外我测试了一下，它支持 Markdown 的导入和导出功能，也就是说，只要我有一个 md 的文件，那我可以立马将它转到这个平台里面去，同时他还支持 pdf、md 文件的导出。</p>
                  <p>这不算什么，我比较欣赏的是 wolai 的一个批量导入的功能，也就是说我可以把我之前所有的 md 文件，然后直接压缩成一个 zip 包。一键上传，wolai 可以解析然后转换，然后所有的文章就导入进来了，牛逼！</p>
                  <h3 id="编辑历史"><a href="#编辑历史" class="headerlink" title="编辑历史"></a>编辑历史</h3>
                  <p>还有一个比较特色的功能是它可以保留每一个 Block 的修改历史，那也就是说如果我们想要回滚一些版本的话，是可以非常方便的查看的。这就类似于他比较好地集成了 Git 版本控制工具，但这个功能得高级版才能支持。</p>
                  <h3 id="情怀"><a href="#情怀" class="headerlink" title="情怀"></a>情怀</h3>
                  <p>还有个加分项，就是整个团队他对一些细节的把控，甚至可以称作一种情怀。</p>
                  <p>比如吧，说他们为了呈现团队成员列表，自己还开发了自己的头像小程序，而且甚至还开发了一个头像创作系统，自己捏自己的脸，放一个对比图吧：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/1624269300376.png" alt=""></p>
                  <p>卧槽，右边那个我感触太深了，我实在是看不下去哪些乱七八糟的图像混杂排布的效果。wolai 这真的牛逼了！我看到之后太舒服了！</p>
                  <p>而且这些头像不是死的！这是他们的头像制作小程序，自己可以给自己捏脸，如图所示：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/1624269329167.png" alt=""></p>
                  <p>这个我觉得做的确实很有情怀了。</p>
                  <p>还有一个，为了将传统文化瑰宝融入 wolai ，他们还与故宫博物院取得联系，并获得文物图片的使用授权。只有在 wolai ，我和你才能….使用故宫文物作为页面题头图。</p>
                  <p><img src="https://qiniu.cuiqingcai.com/1624269349561.png" alt=""></p>
                  <p>卧槽，情怀拉满了！</p>
                  <h3 id="细节"><a href="#细节" class="headerlink" title="细节"></a>细节</h3>
                  <p>另外再说个细节吧，就是这个中英文的混合排版。</p>
                  <p>我其实对于排版是非常严格的，就是我如果看到一个中文和一个英文单词之间没有一定的间距的话，会觉得很难受。</p>
                  <p>所以说在公众号排版的时候，中英文中间我都会留一个间距，比如说就中英文之间加一个空格。</p>
                  <p>不同于 Notion，wolai 它对中英文的排版支持的这个细节把控就做得很到位。比如说我这里敲一个中文和英文，那它会自动的在这两个之间加一个空白，如图所示：</p>
                  <p><img src="https://pic3.zhimg.com/v2-6ad39baccc211a875899c00cd34a784e_b.webp" alt=""></p>
                  <p>这个真的是很细节了！感动。</p>
                  <blockquote>
                    <p>有一点需要说明，wolai 在中英文之间插入的间隔并非实际空格，只是样式上的限定。一旦将文字复制或者导出为本地文件，却是没有空格的。</p>
                  </blockquote>
                  <h2 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h2>
                  <p>现在我已经用起来了，它可以支持多个工作空间，比如我这里就创建了三个，「进击的Coder」可以作为团队型的空间，可以支持多人协作。另外还有两个空间就专门留给我，一个用来写技术，一个用来写生活，如图所示：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/1624269363554.png" alt=""></p>
                  <p>再告诉大家个好消息吧，我在写这篇文章的时候，使用的是 wolai 的个人免费版，它的 Block 数量是有限制的，最多是 5000 个，也就是说，按照一篇文章 100 个 Block 来算，那写 50 篇文章就没 Block 数量了，那就得收费了。</p>
                  <p>但是！！！从 2021 年 6 月 15 日开始！也就是 wolai 一周年到来之际，个人免费版开始不再限制块儿的数量了，那也就是说我们不管写多少文章，那都不会有限制了！</p>
                  <p>我当时看到这个消息的时候，看了下日期，6 月 14 日，哦？幸福来得也太突然了吧！</p>
                  <p>这次我真的不是为这个软件专门打广告的，确实是真心的推荐。</p>
                  <p>我现在也不能完全承诺，以后我就一定会在这个平台上来管理我的所有的文档。因为我刚开始用，可能还得适应一段时间，要是中途遇到什么 bug 也会看看开发团队的解决问题的态度。</p>
                  <p>我也不能承诺这软件一定是你中意的，但至少我看到的这个软件提供的一些功能点是我想要的。各个方面是很契合我的需求，而且里面的一些细节确实让我感动满满。</p>
                  <p>我也不能承诺这个团队以后会不会因为各种原因停止运营和开发这个软件。但我相信，能做出这个产品的团队，能把细节把控到这个地位的团队，也一定不会差了。</p>
                  <p>最后大家如果想试用看看，可以扫个码注册下：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/1624269378576.png" alt=""></p>
                  <p>希望对大家有帮助～</p>
                  <p>更多精彩内容，请关注我的公众号「进击的Coder」和「崔庆才丨静觅」。</p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-06-14 23:54:53" itemprop="dateCreated datePublished" datetime="2021-06-14T23:54:53+08:00">2021-06-14</time>
                </span>
                <span id="/30013.html" class="post-meta-item leancloud_visitors" data-flag-title="分享一个不错的笔记软件" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>5.1k</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>5 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30012.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 个人随笔 <i class="label-arrow"></i>
                  </a>
                  <a href="/30012.html" class="post-title-link" itemprop="url">鸿蒙，即使套壳安卓又能怎样呢？</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>昨天（准确说是前天了），鸿蒙 2.0 发布了，当时没来得及看，睡觉之前看了看回放，说实话这次的更新发布的确让我眼前一亮，甚至自己还有点小心动。因为我现在用的苹果全家桶，所以之前一直对安卓并不太关注，但发布会看到鸿蒙现在建立起的生态还有一些互联的体验，着实让我惊叹一把。甚至我心里都有一点想把自己现有的小米之家的一套以后换成华为全屋智能。</p>
                  <p>别说，还真有可能哈哈。</p>
                  <p>扯远了，说回正题。</p>
                  <p>发布会上宣布了一个消息，那就是现有的很多华为手机都可以开始升级鸿蒙系统，所以一个明显的感觉就是花粉们都开始纷纷尝鲜，从朋友圈就能看得出来大家的期待和热情。</p>
                  <p>然而，还有一些声音又开始热闹起来了，一些人又开始问了，甚至喷起来了——鸿蒙系统 2.0 到底是不是基于安卓？鸿蒙真无耻，明明基于安卓，还把安卓的名字抹掉叫做鸿蒙。看了这些问题和评论，我心里说有点嗤之以鼻吧又觉得太极端，我就单纯觉得争论这个真的挺无聊的，争论这个有什么意义呢？</p>
                  <p>看完这篇文章，你可能就更了解我为什么这么说了。</p>
                  <h2 id="一些渊源"><a href="#一些渊源" class="headerlink" title="一些渊源"></a>一些渊源</h2>
                  <p>因为众所周知的一些原因，美丽国开始打压华为，断供芯片等关键元器件，而且华为不能再使用谷歌的移动服务。</p>
                  <p>断供芯片就不说了，说说后者。</p>
                  <p>谷歌移动服务有一个简称，就是 GMS，英文是 Google Mobile Service，比如 Gmail、Google Play 等等都属于其中。华为不能使用 GMS，这对华为的海外市场可谓是一个巨大的打击。我们国内没法用谷歌的服务自然大家也习以为常了，所以这个变化对国内市场影响不大。然而华为主要消费群体不会局限于国内，国外也是一个非常重要的市场。GMS 之于国外用户就像微信之于国内用户，华为手机没法用 GMS，也就没法用 Google Play，没了 Google Play，那就连应用都没法好好地装了。有人会说，那我把 Google Play 等 App 的 apk 下载下来安装不就好了吗？不行的，没有 GMS，那就相当于就得不到 Google 的认证，所以即使是把 Google Play 的 apk 下载下来也是没法用的。所以，所有 GMS 的生态都没法用了，尤其对于那些已经重度依赖 GMS 的国外用户来说，对买不买华为手机是有非常大的顾虑的。</p>
                  <p>在去年的第一季度，华为的手机销量在全球是位居第一的，然而今年第一季度，华为的全球手机销量已经跌至第六，被三星、苹果、小米、OPPO、VIVO 赶超了，第五的 VIVO 是 10%，而华为今年第一季度已经跌到 4% 了。</p>
                  <p>嗯当然对于这种情形，华为也有自己的应对措施了。比如华为打造了 Huawei Mobile Service，即 HMS，但显然这个相比 GMS 还是有很多不成熟的地方，或者让用户从 GMS 迁移到 HMS，也一定是有很多顾虑和成本的。</p>
                  <p>万般艰难之下，一个重磅消息就诞生了，那就是鸿蒙操作系统的宣布！还记不记得华为宣布鸿蒙的那一天，朋友圈、微博炒的是那么火热，连国家的各个媒体号都在疯狂宣发。为什么？因为当时宣称，这是我们中国人的操作系统！</p>
                  <p>哇，你就想象吧，那种大国自豪感，虽然说网友们平时天天在网上喷来喷去的，但是鸿蒙宣布的那一天，每个人都怀着一种大国自豪感，显得是那么团结。</p>
                  <p>后来一段时间，鸿蒙宣布开放源代码，当时记得有一段时间华为在挤牙膏，放出来了一些源码，当时一些热心网友研究之后就炸锅了，这开发工具怎么和 Android Studio 这么像啊？然后开始从 SDK 或者各处去扒安卓的影子，争先恐后去当第一个扒出安卓蛛丝马迹的人。然后一些套壳安卓的声音就不绝于耳了，骂声变得此起彼伏。我当时其实没有太关注这些，也没去深究这些，但当时给我的感觉就是，某些人就开始揪着套壳安卓这个事不放下，喷来喷去。</p>
                  <p>当时我的态度其实比较坦然，因为我也算懂些安卓，深知从 0 开发出一套安卓系统是一件多么难的事，安卓这发展了十几年才发展成这样子。如果从 0 开始造一个操作系统，即使抛开开发成本，其生态的建立也是极其漫长的过程，如果真有了，而市面上大多数软件都不兼容，微信都没法跑，大批大批的软件运行不了，那谁还会去用呢？几乎是必死的一条路了。所以当时鸿蒙发布会宣布兼容安卓应用的那个时候，我就觉得底层肯定和安卓脱不了干系了，内核肯定基于 Linux，至于多么像，那就得看把安卓改到哪个地步了。</p>
                  <h2 id="是否基于安卓"><a href="#是否基于安卓" class="headerlink" title="是否基于安卓"></a>是否基于安卓</h2>
                  <p>好，那下面就来说说，鸿蒙到底是不是基于安卓。</p>
                  <p>要回答这个问题，我们得首先知道，安卓究竟是什么，要说安卓，就不得不先说一个名字，叫做 AOSP。</p>
                  <p>AOSP，就是 Android Open Source Project 的简称，翻译过来就是安卓开源项目，官网是 <a href="https://source.android.com/。" target="_blank" rel="noopener">https://source.android.com/。</a></p>
                  <p>官网长这样：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/xes4x.png" alt=""></p>
                  <p>AOSP 是开源的，主要是谷歌贡献的，当然其他的厂商也贡献了，比如华为、三星，甚至千千万万普通开发者。</p>
                  <p>那么 AOSP 和我们常说的安卓有什么关系呢？简单来说，安卓是谷歌在 AOSP 的基础上增加了 GMS（前文提到了），AOSP 是开源的，GMS 是闭源的，二者结合起来就成了现在的安卓系统，最纯正最原生的安卓系统大家可以到谷歌官方下载个 Android Studio 开个虚拟机体验下，现在已经发布到 11 了，网址是：<a href="https://developer.android.com/。" target="_blank" rel="noopener">https://developer.android.com/。</a></p>
                  <p>OK，但是我们平常用的一些手机的系统和原生安卓也还是有些许不同的，比如小米的 MIUI、三星 OneUI、OPPO 的 ColorOS，锤子的 Smartisan OS，这些都是基于 AOSP 开发的 ROM，而且用也上了 GMS，虽然国内因为某些原因没法用，但它也是有的，况且它们也没有像华为一样被禁。另外小米等公司也大大方方承认这是基于 Android 的，所以你可以看到小米手机的系统里面就写着，MIUI 什么版本，安卓内核什么版本。</p>
                  <p>OK，那鸿蒙呢？因为安卓 = AOSP + GMS，而 GMS 已经被禁了啊，那何必还称自己基于安卓呢？是吧，那就叫鸿蒙。</p>
                  <p>是的，就是这样。</p>
                  <p>所以，AOSP，它是开源的，谷歌放弃了它的所有权。AOSP 人人都能用，人人都能基于它开发。可以认为，AOSP 是安卓和鸿蒙的妈，安卓和鸿蒙是 AOSP 的孩子，只不过不同一个时间段，安卓在 AOSP 基础上多了个 GMS，而鸿蒙没有。</p>
                  <p>很多人就是像通过 AOSP、安卓、鸿蒙之间的关系想努力证明安卓和鸿蒙是一样的，鸿蒙是套壳安卓的，何必呢？</p>
                  <p>而且，我们必须要承认，华为的鸿蒙基于 AOSP 做了很多修改，基于鸿蒙的一些设计战略，分布式互联系统的出发点，少不了底层的一些修改和优化。至于难度怎么样？小米、锤子人家都能做成这样，对于华为这么大的公司来说，还会难吗？</p>
                  <p>而且我相信，将来鸿蒙虽然基于 AOSP 改，但未来也会离 AOSP 越来越远，甚至慢慢面目全非都有可能。</p>
                  <h2 id="鸿蒙的核心优势"><a href="#鸿蒙的核心优势" class="headerlink" title="鸿蒙的核心优势"></a>鸿蒙的核心优势</h2>
                  <p>但其实我想说的重点不是上面的内容，不是为鸿蒙和安卓的区分做一个辩驳，因为我认为这是没有意义的。</p>
                  <p>因为真正有意义的点在于，我们应该关注华为借着鸿蒙，怎样发挥了公司的本身优势，建立了怎样一个基于鸿蒙的巨大生态。</p>
                  <p>华为不会纠结于到底是不是真正自己从 0 开始实现一个系统，这真的没有意义。华为是站在 AOSP 的基础上，想着怎么把自己的优势发挥出来，怎么将无法使用 GMS 的损失降低，怎么建立一套新的生态体系，怎样重新让华为的市场振作起来，甚至还可以证明，我们中国做的系统也一样可以引起一些可以称之为颠覆性的浪潮。</p>
                  <p>OK，大家相比也看到了发布会的一些演示了，我觉得华为有一个点做得非常好，那就是充分发挥了自己公司的优势。</p>
                  <p>华为是什么公司？是一家通信公司，通信技术在世界都是名列前茅，而且华为也一直在着眼于打造物联网全屋智能。</p>
                  <p>所以，这些碰撞在一起，将鸿蒙定位成一个分布式智能终端操作系统，这就一下子把鸿蒙的局限性从安卓手机这个层面抬高了，格局就不一样了。</p>
                  <p><img src="https://qiniu.cuiqingcai.com/oe61o.jpg" alt=""></p>
                  <p>华为很聪明，鸿蒙一下子被抬升到这个高度，那自然把名字也扩展到其他的设备上吧。</p>
                  <ul>
                    <li>
                      <p>比如说，华为家的智能手表，其实本来说智能也智能，但没个很正式的名字，那就叫鸿蒙！</p>
                    </li>
                    <li>
                      <p>比如说，智能家电里面的芯片吧，其实就是个嵌入式的设备，很多厂商都能做啊，智能饮水机、智能燃气灶，智能加湿器，小米家不也做得挺好的吗，也能通过 App 控制，但你说小米家的智能加湿器里面运行的系统叫啥名？说不上来。但华为就不一样了，鸿蒙的定位上来了，格局上来了，那我们就叫它鸿蒙系统啊，名字嘛，就是个叫法而已。</p>
                    </li>
                  </ul>
                  <p>好家伙，这名字一改，那我岂不是就可以对外宣称说，我们鸿蒙系统可以运行在手表，运行在所有的智能 IoT 设备上了，鸿蒙一下子逼格又提升了一个档次，不但格局上来了，技术也显得更牛逼了。鸿蒙还能兼容这么多平台，一听就牛逼吧。</p>
                  <p>所以，我还是很佩服华为的这个思路的，高！实在是高！</p>
                  <p>但光有战略不够啊，那得实打实做出点东西才行对吧。</p>
                  <p>有，这个必须有！而且正好撞枪口上了，通信和物联网，就是华为的优势点所在。</p>
                  <p>在鸿蒙基础上，华为配合上自家的通信技术的加持，将设备联动做得尽善尽美，基于超级终端这个定义，将所有的设备联系在一起。</p>
                  <ul>
                    <li>
                      <p>比如说，手机和大屏 Pad 的联动，华为把手机在 Pad 的镜像和操作做到了极低的延迟和极高的流畅度，同时加上软件的一些优化，实现数据的共享。</p>
                    </li>
                    <li>
                      <p>比如说，手机和耳机和电视的联动，通过手机作为中枢，将视频流、音频流的传输和同步做到了极致，实现了无缝的转接体验。</p>
                    </li>
                    <li>
                      <p>比如说，华为手机、无人机组成的多机位拍摄，将硬件和软件之间的关系解耦，每个终端都能自由选择连接的硬件，这其中也是需要非常强的通信技术。</p>
                    </li>
                  </ul>
                  <p>这就是把自己最牛逼的技术正好最大化地发挥出来了啊！</p>
                  <p>鸿蒙发布会上提到了两个核心技术：</p>
                  <ul>
                    <li>软时钟同步</li>
                    <li>抗干扰算法</li>
                  </ul>
                  <p>软时钟同步是通信行业非常重要的技术指标，另外基于 5G 的时钟同步更为重要，该项技术能极大地影响通话体验、音视频的同步效果。华为通信出身，又是 5G 引领者，搞这个自然不在话下了。之于抗干扰算法，不必多说，这属于无线通信的范畴，将自己的技术应用到鸿蒙也是顺理成章了。</p>
                  <p>所以，最后大家可以看到，华为借着鸿蒙，把自家最牛逼的技术实现了完美的落地，打造了物联网生态，又带动了自家全屋智能家居的发展，拉高了鸿蒙的布局，又证明了鸿蒙的确能行，还能顺便给国家注入一剂强心剂！一举多得。</p>
                  <p>这才是鸿蒙真正的优势所在。</p>
                  <p>这才是鸿蒙真正的战略所在。</p>
                  <p>这才是鸿蒙对消费者、对技术发展、对国家、乃至对世界的意义。</p>
                  <p>Oh，这时候你再跟我说，鸿蒙是套壳安卓，你看看我还理你嘛？</p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-06-02 09:17:06" itemprop="dateCreated datePublished" datetime="2021-06-02T09:17:06+08:00">2021-06-02</time>
                </span>
                <span id="/30012.html" class="post-meta-item leancloud_visitors" data-flag-title="鸿蒙，即使套壳安卓又能怎样呢？" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>4.1k</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>4 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30011.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 个人记录 <i class="label-arrow"></i>
                  </a>
                  <a href="/30011.html" class="post-title-link" itemprop="url">微信最新版可以刷朋友圈了！</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>今天看到一个消息，说微信 PC 版最新版本可以刷朋友圈了，还加了许多新功能，简直喜大普奔，我赶紧装来试试。</p>
                  <p>不过可能让大家觉得稍有遗憾的是，现在发布的只支持 Mac 版，而且处在内测阶段，Windows 版的后续才会发布。</p>
                  <p>别问我怎么搞到的，看完这篇文章你也能立马获取。</p>
                  <p>装完之后，打开微信就提示了最新版本的更新界面：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/bvjmo.png" alt=""></p>
                  <p>这是 Mac 上的重大更新：</p>
                  <ul>
                    <li>可以刷朋友圈了</li>
                    <li>看视频号的视频和直播了</li>
                    <li>可以支持深色模式了</li>
                  </ul>
                  <p>就是主要这么几大更新，我们来一起看看。</p>
                  <p>首先就是深色模式，这个简直太舒服了，现在很多 Mac 软件都已经适配了深色模式，唯独微信迟迟没有更新，这下终于有了！</p>
                  <p>我把 Mac 调整到深色主题，然后微信就会跟着变化了。</p>
                  <p>深色模式是这个样子的：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/4gwjz.png" alt=""></p>
                  <p>很完美，以后深夜再也不用面对那明晃晃的白色聊天窗口了。</p>
                  <p>接下来就是朋友圈，在侧栏出现了这样的小图标：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/itcsb.png" alt=""></p>
                  <p>一点就会弹出一个新的窗口，而不是呈现在右侧，窗口是张这个样子的：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/4nrnh.png" alt=""></p>
                  <p>在右上角有刷新按钮和消息按钮，消息按钮点击之后同样以浮窗的形式呈现：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/0pqqz.png" alt=""></p>
                  <p>另外朋友圈点赞和评论的操作基本上和手机上是一样的：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/l25u3.png" alt=""></p>
                  <p>小视频播放也不在话下：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/pxqog.png" alt=""></p>
                  <p>嗯，整体感觉还是不错的，以后朋友圈就可以在电脑上看了。</p>
                  <p>接下来就是视频号，测试了一下转发了一个视频号的内容，显示是这样的：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/zgzgf.png" alt=""></p>
                  <p>然后还是以弹窗的形式呈现：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/koidf.png" alt=""></p>
                  <p>不过只有转发的操作，没法点赞和评论。</p>
                  <p>然后就是直播，转发的直播在聊天中是这样的：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/3c1dl.png" alt=""></p>
                  <p>点开之后显示是这样的：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/0uhpc.png" alt=""></p>
                  <p>这个是我的视频号哈，就简单开了一下直播，照的是家里的房顶，没啥实质性的东西，就仅做测试哈。</p>
                  <p>整体体验下来感觉这个更新还是很给力的，尤其对我有用的就是看朋友圈的功能了。</p>
                  <p>但是稍微有点遗憾的是，还不支持发朋友圈的功能，希望微信能快快支持。</p>
                  <p>最后，如果你也想体验一下，请在本公号回复“微信最新版”获取下载地址，大家晚安！</p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-03-11 15:37:07" itemprop="dateCreated datePublished" datetime="2021-03-11T15:37:07+08:00">2021-03-11</time>
                </span>
                <span id="/30011.html" class="post-meta-item leancloud_visitors" data-flag-title="微信最新版可以刷朋友圈了！" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>729</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>1 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30009.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 技术杂谈 <i class="label-arrow"></i>
                  </a>
                  <a href="/30009.html" class="post-title-link" itemprop="url">推荐一个工具 Mockoon，一分钟开发 API</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2>
                  <p>有时候我会碰到快速搭建测试服务的需求，比如像这样：</p>
                  <blockquote>
                    <p> 搭建一个 HTTP Service，这个服务器可以 run 在本地，也需要公网可以访问，请求该服务可以得到一组自定义的 JSON 数据。不为别的，就为临时快速做点测试用。</p>
                  </blockquote>
                  <p>这时候我想要以最短的速度完成，比如一分钟就写出来，这时候可以怎么做？</p>
                  <p>比如大家可能想到了，跑个 Flask 或者 FastAPI，把示例代码改改，然后 Python 一个命令就跑起来了。</p>
                  <p>比如代码像这样：</p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">from</span> typing <span class="keyword">import</span> Optional</span><br><span class="line"><span class="keyword">from</span> fastapi <span class="keyword">import</span> FastAPI</span><br><span class="line"></span><br><span class="line">app = FastAPI()</span><br><span class="line"></span><br><span class="line"><span class="meta">@app.get("/")</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">read_root</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">return</span> &#123;<span class="string">"Hello"</span>: <span class="string">"World"</span>&#125;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>然后我用命令跑起来：</p>
                  <figure class="highlight ada">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">uvicorn main:app <span class="comment">--reload</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>OK，说好的自定义 JSON 就已经完成了。</p>
                  <p>可是我要加需求了，我要支持跨域访问，怎么做？这时候我可能又要去搜 FastAPI cors 关键字，然后找到 <a href="https://fastapi.tiangolo.com/tutorial/cors/" target="_blank" rel="noopener">https://fastapi.tiangolo.com/tutorial/cors/</a> 文档，然后加上类似这样的一些配置：</p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">from</span> fastapi.middleware.cors <span class="keyword">import</span> CORSMiddleware</span><br><span class="line"></span><br><span class="line">app = FastAPI()</span><br><span class="line"></span><br><span class="line">origins = [</span><br><span class="line">    <span class="string">"http://localhost.tiangolo.com"</span>,</span><br><span class="line">    <span class="string">"https://localhost.tiangolo.com"</span>,</span><br><span class="line">    <span class="string">"http://localhost"</span>,</span><br><span class="line">    <span class="string">"http://localhost:8080"</span>,</span><br><span class="line">]</span><br><span class="line"></span><br><span class="line">app.add_middleware(</span><br><span class="line">    CORSMiddleware,</span><br><span class="line">    allow_origins=origins,</span><br><span class="line">    allow_credentials=<span class="literal">True</span>,</span><br><span class="line">    allow_methods=[<span class="string">"*"</span>],</span><br><span class="line">    allow_headers=[<span class="string">"*"</span>],</span><br><span class="line">)</span><br><span class="line">...</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>也还行对吧。</p>
                  <p>那现在我又改需求了，我要返回一张图片怎么办？我要返回一个文件怎么办？我要 HTTPS 访问怎么办？</p>
                  <p>甚至说，我代码写的不熟怎么办？为了搞这个 API Service 我得花大半个小时，太得不偿失了吧。</p>
                  <p>毕竟大家都挺忙的。</p>
                  <p>所以我会想，这些简单的事，为啥要写代码解决啊？难道没有工具通过一些可视化配置来完成吗？</p>
                  <p>如果你也有这个痛点，请继续向下看。</p>
                  <p>如果你没有，既然来都来了，客官继续看看嘛…</p>
                  <h2 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h2>
                  <p>所以现在我的需求是：我想通过一个便捷的工具快速搭建一个 API Server，能配置返回 JSON 或者图片或者文件等等，甚至说动态路由、动态转发等等功能，如果这些步骤还能通过可视化图形界面来搞定就更好了。</p>
                  <p>来了，今天就给大家推荐一个工具，叫做 Mockoon。</p>
                  <p>Mockoon 是一个可以通过图形化界面帮我们快速搭建 API 服务的工具，支持数据模拟、路由解析、跨域访问、HTTPS、自定义延时、Docker 等等各种你想要的功能，同时支持支持 Windows、Mac、Linux，页面整体是这样子的：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/6hkae.png" alt=""></p>
                  <p>这布局，和 PostMan 有异曲同工之妙啊。</p>
                  <p>比如左侧我们可以配置一个个请求列表，点进去可以在右侧配置详情，比如配置是 GET 还是 POST 请求，path 是什么，Response Body 是什么，Response Headers 是什么，另外还有一些规则和基础设置。</p>
                  <p><img src="https://qiniu.cuiqingcai.com/lyryz.png" alt=""></p>
                  <p>另外在最上面我可以配置运行的 host 和 port，然后左上角还有一个运行按钮，一点就相当于启动了 Server 了，启动之后按钮就会变成红色，再按一下就会停止，比如这里我就配置了运行在本地 3894 端口：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/4osrb.png" alt=""></p>
                  <p>然后我修改下 Body：</p>
                  <figure class="highlight json">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"data"</span>: [</span><br><span class="line">    &#123;<span class="attr">"id"</span>: <span class="number">1</span>, <span class="attr">"name"</span>: <span class="string">"Picture3"</span>, <span class="attr">"url"</span>: <span class="string">"https://qiniu.cuiqingcai.com/l4ol8.jpg"</span>&#125;,</span><br><span class="line">    &#123;<span class="attr">"id"</span>: <span class="number">2</span>, <span class="attr">"name"</span>: <span class="string">"Picture2"</span>, <span class="attr">"url"</span>: <span class="string">"https://qiniu.cuiqingcai.com/zy2w3.jpg"</span>&#125;,</span><br><span class="line">    &#123;<span class="attr">"id"</span>: <span class="number">3</span>, <span class="attr">"name"</span>: <span class="string">"Picture1"</span>, <span class="attr">"url"</span>: <span class="string">"https://qiniu.cuiqingcai.com/v10oo.jpg"</span>&#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里我返回一个 JSON 格式的列表，包含了三个字段。</p>
                  <p>然后接下来我要配置跨域访问，就加一个 Response Header：</p>
                  <figure class="highlight ada">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">Access</span>-Control-Allow-Origin: <span class="string">'*'</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>然后点击左上角的运行按钮就成了。</p>
                  <p>Mockoon 还提供了快捷访问的功能，接着点右上角的打开按钮：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/zx6du.png" alt=""></p>
                  <p>浏览器就打开了，然后数据就看到了：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/eh646.png" alt=""></p>
                  <p>咔咔咔，就这样，我们通过非常简单的可视化配置就完成了 API Server 的搭建，熟练的话一分钟就完成了。</p>
                  <p>另外还有太多功能，比如 HTTPS、多请求处理、日志、路由、模板配置这里就不再一一叙述了，用到的时候查文档就好啦：</p>
                  <ul>
                    <li>Cors：<a href="https://mockoon.com/docs/latest/cors/" target="_blank" rel="noopener">https://mockoon.com/docs/latest/cors/</a></li>
                    <li>HTTPS：<a href="https://mockoon.com/docs/latest/https/" target="_blank" rel="noopener">https://mockoon.com/docs/latest/https/</a></li>
                    <li>Import/Export Data：<a href="https://mockoon.com/docs/latest/import-export-data/" target="_blank" rel="noopener">https://mockoon.com/docs/latest/import-export-data/</a></li>
                    <li>Mutiple Response: <a href="https://mockoon.com/docs/latest/multiple-responses/" target="_blank" rel="noopener">https://mockoon.com/docs/latest/multiple-responses/</a></li>
                    <li>Proxy Mode: <a href="https://mockoon.com/docs/latest/proxy-mode/" target="_blank" rel="noopener">https://mockoon.com/docs/latest/proxy-mode/</a></li>
                    <li>Request logging: <a href="https://mockoon.com/docs/latest/requests-logging/" target="_blank" rel="noopener">https://mockoon.com/docs/latest/requests-logging/</a></li>
                    <li>Response Headers: <a href="https://mockoon.com/docs/latest/response-headers/" target="_blank" rel="noopener">https://mockoon.com/docs/latest/response-headers/</a></li>
                    <li>Routing: <a href="https://mockoon.com/docs/latest/routing/" target="_blank" rel="noopener">https://mockoon.com/docs/latest/routing/</a></li>
                    <li>Templating: <a href="https://mockoon.com/docs/latest/templating/" target="_blank" rel="noopener">https://mockoon.com/docs/latest/templating/</a></li>
                  </ul>
                  <p>另外 Mockoon 还支持命令行，比如通过 mockoon-cli 就可以快速创建一个 API Server，如图所示：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/5mmeo.png" alt="img"></p>
                  <p>命令行的使用和安装可以参考：<a href="https://github.com/mockoon/cli#installation" target="_blank" rel="noopener">https://github.com/mockoon/cli#installation</a></p>
                  <p>以上便是这个工具的简单介绍，更多功能等待你的探索！</p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-03-01 15:37:07" itemprop="dateCreated datePublished" datetime="2021-03-01T15:37:07+08:00">2021-03-01</time>
                </span>
                <span id="/30009.html" class="post-meta-item leancloud_visitors" data-flag-title="推荐一个工具 Mockoon，一分钟开发 API" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>2.7k</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>2 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30008.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 技术杂谈 <i class="label-arrow"></i>
                  </a>
                  <a href="/30008.html" class="post-title-link" itemprop="url">介绍一个超强的 Youtube 下载工具 pytube</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>在这里介绍一个工具，使用它我们可以非常方便地使用 Python 下载 Youtube 的视频，叫做 pytube。</p>
                  <p>利用它我们可以实现如下功能：</p>
                  <ul>
                    <li>支持 progresive 和 DASH 视频流的下载</li>
                    <li>支持下载完整的播放列表</li>
                    <li>可以处理下载进行中和下载完成的回调</li>
                    <li>提供命令行直接执行下载</li>
                    <li>支持下载字幕</li>
                    <li>支持将字幕输出为 srt 格式</li>
                    <li>获取视频缩略图</li>
                  </ul>
                  <p>下面我们就来详细了解一下它的使用方法。</p>
                  <h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2>
                  <p>首先看下安装过程，安装非常简单，只需要使用 pip3 安装即可，命令如下：</p>
                  <figure class="highlight cmake">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">pip3 <span class="keyword">install</span> pytube</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>或者直接源码安装也行：</p>
                  <figure class="highlight awk">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">pip3 install git+https:<span class="regexp">//gi</span>thub.com<span class="regexp">/pytube/</span>pytube</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>安装完成之后就可以使用 pytube 命令了。</p>
                  <h2 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h2>
                  <p>这里先介绍两个最常见的用法，那就是直接使用 pytube 命令，它可以用来下载单个 Yotube 视频或者视频列表。</p>
                  <p>比如这是一个视频 <a href="https://youtube.com/watch?v=2lAe1cqCOXo，截图如下：" target="_blank" rel="noopener">https://youtube.com/watch?v=2lAe1cqCOXo，截图如下：</a></p>
                  <p><img src="https://qiniu.cuiqingcai.com/mtoy6.png" alt=""></p>
                  <p>我们可以直接使用命令下载：</p>
                  <figure class="highlight groovy">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">pytube <span class="string">https:</span><span class="comment">//www.youtube.com/watch?v=2lAe1cqCOXo</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>很快视频就能被下载下来了：</p>
                  <figure class="highlight angelscript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">Loading video...</span><br><span class="line">YouTube Rewind <span class="number">2019</span> For the Record  YouTubeRewind.mp4 | <span class="number">83</span> MB</span><br><span class="line"> ↳ |█████████                                   | <span class="number">21.4</span>%</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>同样地，pytube 还能下载播放列表，比如这是一个播放列表 <a href="https://www.youtube.com/playlist?list=PLS1QulWo1RIaJECMeUT4LFwJ-ghgoSH6n，截图如下：" target="_blank" rel="noopener">https://www.youtube.com/playlist?list=PLS1QulWo1RIaJECMeUT4LFwJ-ghgoSH6n，截图如下：</a></p>
                  <p><img src="https://qiniu.cuiqingcai.com/ttuj0.png" alt=""></p>
                  <p>使用 pytube 同样可以轻松下载：</p>
                  <figure class="highlight vim">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">pytube http<span class="variable">s:</span>//www.youtube.<span class="keyword">com</span>/playlist?<span class="keyword">list</span>=PLS1QulWo1RIaJECMeUT4LFwJ-ghgoSH6n</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>它可以解析播放列表，然后一个个下载下来：</p>
                  <figure class="highlight angelscript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">Loading playlist...</span><br><span class="line">Python Tutorial <span class="keyword">for</span> Beginners <span class="number">1</span> - Getting Started <span class="keyword">and</span> Installing Python (For Absolute Beginners).mp4 | <span class="number">63</span> MB</span><br><span class="line"> ↳ |████████████████████████████████████████████| <span class="number">100.0</span>%</span><br><span class="line">Python Tutorial <span class="keyword">for</span> Beginners <span class="number">2</span> - Numbers <span class="keyword">and</span> Math <span class="keyword">in</span> Python.mp4 | <span class="number">11</span> MB</span><br><span class="line"> ↳ |████████████████████████████████████████████| <span class="number">100.0</span>%</span><br><span class="line">Python Tutorial <span class="keyword">for</span> Beginners <span class="number">3</span> - Variables <span class="keyword">and</span> Inputs.mp4 | <span class="number">15</span> MB</span><br><span class="line"> ↳ |████████████████████████████████████████████| <span class="number">100.0</span>%</span><br><span class="line">Python Tutorial <span class="keyword">for</span> Beginners <span class="number">4</span> - Built-<span class="keyword">in</span> Modules <span class="keyword">and</span> Functions.mp4 | <span class="number">16</span> MB</span><br><span class="line"> ↳ |████████████████████████████████████████████| <span class="number">100.0</span>%</span><br><span class="line">Python Tutorial <span class="keyword">for</span> Beginners <span class="number">5</span> - Save <span class="keyword">and</span> Run Python files py.mp4 | <span class="number">37</span> MB</span><br><span class="line"> ↳ |████████████████████████████████████████████| <span class="number">100.0</span>%</span><br><span class="line">Python Tutorial <span class="keyword">for</span> Beginners <span class="number">6</span> - Strings.mp4 | <span class="number">78</span> MB</span><br><span class="line"> ↳ |███████████████████████████████████         | <span class="number">79.6</span>%</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>当然除了默认的命令配置，还可以支持查看 list，查看字幕，筛选语言等等，具体的命令如下：</p>
                  <figure class="highlight livecodeserver">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">usage: pytube [-h] [<span class="comment">--version] [--itag ITAG] [-r RESOLUTION] [-l] [-v]</span></span><br><span class="line">              [<span class="comment">--logfile LOGFILE] [--build-playback-report] [-c CAPTION_CODE]</span></span><br><span class="line">              [-lc] [-t TARGET] [-<span class="keyword">a</span> [AUDIO]] [-f [FFMPEG]]</span><br><span class="line">              [url]</span><br><span class="line"></span><br><span class="line">Command <span class="built_in">line</span> application <span class="built_in">to</span> download youtube videos.</span><br><span class="line"></span><br><span class="line">positional arguments:</span><br><span class="line">  url                   The YouTube /watch <span class="keyword">or</span> /playlist url</span><br><span class="line"></span><br><span class="line">optional arguments:</span><br><span class="line">  -h, <span class="comment">--help            show this help message and exit</span></span><br><span class="line">  <span class="comment">--version             show program's version number and exit</span></span><br><span class="line">  <span class="comment">--itag ITAG           The itag for the desired stream</span></span><br><span class="line">  -r RESOLUTION, <span class="comment">--resolution RESOLUTION</span></span><br><span class="line">                        The resolution <span class="keyword">for</span> <span class="keyword">the</span> desired stream</span><br><span class="line">  -l, <span class="comment">--list            The list option causes pytube cli to return a list of</span></span><br><span class="line">                        streams available <span class="built_in">to</span> download</span><br><span class="line">  -v, <span class="comment">--verbose         Verbosity level, use up to 4 to increase logging -vvvv</span></span><br><span class="line">  <span class="comment">--logfile LOGFILE     logging debug and error messages into a log file</span></span><br><span class="line">  <span class="comment">--build-playback-report</span></span><br><span class="line">                        Save <span class="keyword">the</span> html <span class="keyword">and</span> js <span class="built_in">to</span> disk</span><br><span class="line">  -c CAPTION_CODE, <span class="comment">--caption-code CAPTION_CODE</span></span><br><span class="line">                        Download srt captions <span class="keyword">for</span> given language code. Prints</span><br><span class="line">                        available language codes <span class="keyword">if</span> no argument given</span><br><span class="line">  -lc, <span class="comment">--list-captions  List available caption codes for a video</span></span><br><span class="line">  -t TARGET, <span class="comment">--target TARGET</span></span><br><span class="line">                        The output <span class="built_in">directory</span> <span class="keyword">for</span> <span class="keyword">the</span> downloaded stream.</span><br><span class="line">                        Default is current working <span class="built_in">directory</span></span><br><span class="line">  -<span class="keyword">a</span> [AUDIO], <span class="comment">--audio [AUDIO]</span></span><br><span class="line">                        Download <span class="keyword">the</span> audio <span class="keyword">for</span> <span class="keyword">a</span> given <span class="built_in">URL</span> <span class="keyword">at</span> <span class="keyword">the</span> highest</span><br><span class="line">                        bitrate availableDefaults <span class="built_in">to</span> mp4 <span class="built_in">format</span> <span class="keyword">if</span> <span class="literal">none</span> is</span><br><span class="line">                        specified</span><br><span class="line">  -f [FFMPEG], <span class="comment">--ffmpeg [FFMPEG]</span></span><br><span class="line">                        Downloads <span class="keyword">the</span> audio <span class="keyword">and</span> video stream <span class="keyword">for</span> resolution</span><br><span class="line">                        providedIf no resolution is provided, downloads <span class="keyword">the</span></span><br><span class="line">                        best resolutionRuns <span class="keyword">the</span> <span class="keyword">command</span> <span class="title">line</span> <span class="title">program</span> <span class="title">ffmpeg</span> <span class="title">to</span></span><br><span class="line">                        <span class="built_in">combine</span> <span class="keyword">the</span> audio <span class="keyword">and</span> video</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>更多详细的说明可以参考官方文档：<a href="https://python-pytube.readthedocs.io/en/latest/user/cli.html" target="_blank" rel="noopener">https://python-pytube.readthedocs.io/en/latest/user/cli.html</a></p>
                  <h2 id="代码使用"><a href="#代码使用" class="headerlink" title="代码使用"></a>代码使用</h2>
                  <p>当然除了这些，pytube 还支持以 Python 编程的方式来进行下载，同时提供了便捷的链式操作，比如这段代码：</p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="keyword">from</span> pytube <span class="keyword">import</span> YouTube</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>YouTube(<span class="string">'https://youtu.be/2lAe1cqCOXo'</span>).streams.first().download()</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>yt = YouTube(<span class="string">'http://youtube.com/watch?v=2lAe1cqCOXo'</span>)</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>yt.streams</span><br><span class="line"><span class="meta">... </span>.filter(progressive=<span class="literal">True</span>, file_extension=<span class="string">'mp4'</span>)</span><br><span class="line"><span class="meta">... </span>.order_by(<span class="string">'resolution'</span>)</span><br><span class="line"><span class="meta">... </span>.desc()</span><br><span class="line"><span class="meta">... </span>.first()</span><br><span class="line"><span class="meta">... </span>.download()</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里大家可以看到，要使用 pytube，只需要导入其中的 Youtube 这个类，然后传入 URL 声明 Youtube 对象就好了。接着我们可以直接调用其 streams 方法获取所有的视频源，然后可以通过 first 或者 filter 或者 order 等进行排序或筛选等处理，然后最后调用 download 方法就可以执行下载了。</p>
                  <p>下面我们来剖析一下具体是怎么回事。</p>
                  <p>首先我们来声明一下 YouTube 对象：</p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="keyword">from</span> pytube <span class="keyword">import</span> YouTube</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>yt = YouTube(<span class="string">'https://youtu.be/2lAe1cqCOXo'</span>)</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>yt</span><br><span class="line">&lt;pytube.__main__.YouTube object at <span class="number">0x7f88901e9890</span>&gt;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>然后看看 streams 是什么：</p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>yt.streams</span><br><span class="line">[&lt;Stream: itag=<span class="string">"18"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"360p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"avc1.42001E"</span> acodec=<span class="string">"mp4a.40.2"</span> progressive=<span class="string">"True"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"22"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"720p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"avc1.64001F"</span> acodec=<span class="string">"mp4a.40.2"</span> progressive=<span class="string">"True"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"137"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"1080p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"avc1.640028"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"248"</span> mime_type=<span class="string">"video/webm"</span> res=<span class="string">"1080p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"vp9"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"399"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"1080p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"av01.0.08M.08"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"136"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"720p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"avc1.4d401f"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"247"</span> mime_type=<span class="string">"video/webm"</span> res=<span class="string">"720p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"vp9"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"398"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"720p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"av01.0.05M.08"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"135"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"480p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"avc1.4d401e"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"244"</span> mime_type=<span class="string">"video/webm"</span> res=<span class="string">"480p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"vp9"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"397"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"480p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"av01.0.04M.08"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"134"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"360p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"avc1.4d401e"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"243"</span> mime_type=<span class="string">"video/webm"</span> res=<span class="string">"360p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"vp9"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"396"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"360p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"av01.0.01M.08"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"133"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"240p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"avc1.4d4015"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"242"</span> mime_type=<span class="string">"video/webm"</span> res=<span class="string">"240p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"vp9"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"395"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"240p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"av01.0.00M.08"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"160"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"144p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"avc1.4d400c"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"278"</span> mime_type=<span class="string">"video/webm"</span> res=<span class="string">"144p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"vp9"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"394"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"144p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"av01.0.00M.08"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;, &lt;Stream: itag=<span class="string">"140"</span> mime_type=<span class="string">"audio/mp4"</span> abr=<span class="string">"128kbps"</span> acodec=<span class="string">"mp4a.40.2"</span> progressive=<span class="string">"False"</span> type=<span class="string">"audio"</span>&gt;, &lt;Stream: itag=<span class="string">"249"</span> mime_type=<span class="string">"audio/webm"</span> abr=<span class="string">"50kbps"</span> acodec=<span class="string">"opus"</span> progressive=<span class="string">"False"</span> type=<span class="string">"audio"</span>&gt;, &lt;Stream: itag=<span class="string">"250"</span> mime_type=<span class="string">"audio/webm"</span> abr=<span class="string">"70kbps"</span> acodec=<span class="string">"opus"</span> progressive=<span class="string">"False"</span> type=<span class="string">"audio"</span>&gt;, &lt;Stream: itag=<span class="string">"251"</span> mime_type=<span class="string">"audio/webm"</span> abr=<span class="string">"160kbps"</span> acodec=<span class="string">"opus"</span> progressive=<span class="string">"False"</span> type=<span class="string">"audio"</span>&gt;]</span><br><span class="line">&gt;&gt; type(yt.streams)</span><br><span class="line">&lt;<span class="class"><span class="keyword">class</span> '<span class="title">pytube</span>.<span class="title">query</span>.<span class="title">StreamQuery</span>'&gt;</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>可以看到这里 streams 是一个 StreamQuery 对象，然后输出出来看起来像是一个列表，其中包含了一个个 stream 对象。</p>
                  <p>所以，StreamQuery 就是我们需要重点关注的对象了。</p>
                  <p>比如接下来我们使用 filter 或者 order_by 方法进行处理：</p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>type(yt.streams.filter(file_extension=<span class="string">'mp4'</span>))</span><br><span class="line">&lt;<span class="class"><span class="keyword">class</span> '<span class="title">pytube</span>.<span class="title">query</span>.<span class="title">StreamQuery</span>'&gt;</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>可以看到它依然还是一个 StreamQuery 对象。</p>
                  <p>然后根据分辨率进行排序：</p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>type(yt.streams.filter(file_extension=<span class="string">'mp4'</span>).order_by(<span class="string">'resolution'</span>))</span><br><span class="line">&lt;<span class="class"><span class="keyword">class</span> '<span class="title">pytube</span>.<span class="title">query</span>.<span class="title">StreamQuery</span>'&gt;</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>还是一样，返回的还是 StreamQuery 对象。</p>
                  <p>这下明白为什么它可以进行链式操作了吧，因为每次 filter 或者 order_by 对象返回的依然还是 StreamQuery 对象，依然还是可以调用对应的方法的。</p>
                  <p>不过也不是每一个都是支持链式操作的，比如接下来我们对 StreamQuery 对象调用 first 方法：</p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>yt.streams.first()</span><br><span class="line">&lt;Stream: itag=<span class="string">"18"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"360p"</span> fps=<span class="string">"24fps"</span> vcodec=<span class="string">"avc1.42001E"</span> acodec=<span class="string">"mp4a.40.2"</span> progressive=<span class="string">"True"</span> type=<span class="string">"video"</span>&gt;</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>type(yt.streams.first())</span><br><span class="line">&lt;<span class="class"><span class="keyword">class</span> '<span class="title">pytube</span>.<span class="title">streams</span>.<span class="title">Stream</span>'&gt;</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>看到这里返回的就是单个 Stream 了。</p>
                  <p>对于 Stream 对象，我们最常用的就是 download 方法了。</p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">yt.streams.first().download()</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>调用完毕之后，视频就会下载在运行目录中。</p>
                  <p>以上我们就介绍了利用命令行和代码进行视频下载的过程。</p>
                  <h2 id="更多"><a href="#更多" class="headerlink" title="更多"></a>更多</h2>
                  <p>当然这个库还有很多强大的功能，都在文档 <a href="https://python-pytube.readthedocs.io/en/latest/" target="_blank" rel="noopener">https://python-pytube.readthedocs.io/en/latest/</a> 写得很清楚了，这里带大家稍微看下。</p>
                  <p>比如获取视频的属性：</p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>yt.title</span><br><span class="line">YouTube Rewind <span class="number">2019</span>: For the Record | <span class="comment">#YouTubeRewind</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>获取视频的缩略图：</p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>yt.thumbnail_url</span><br><span class="line"><span class="string">'https://i.ytimg.com/vi/2lAe1cqCOXo/maxresdefault.jpg'</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>在初始化的时候设置处理方法或者设置代理：</p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>yt = YouTube(</span><br><span class="line">  <span class="string">'http://youtube.com/watch?v=2lAe1cqCOXo'</span>,</span><br><span class="line">  on_progress_callback=progress_func,</span><br><span class="line">  on_complete_callback=complete_func,</span><br><span class="line">  proxies=my_proxies</span><br><span class="line">)</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>关于 filter 的一些用法，可以参考 <a href="https://python-pytube.readthedocs.io/en/latest/user/streams.html#filtering-streams，比如说过滤只保留有音频的流媒体：" target="_blank" rel="noopener">https://python-pytube.readthedocs.io/en/latest/user/streams.html#filtering-streams，比如说过滤只保留有音频的流媒体：</a></p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>yt.streams.filter(only_audio=<span class="literal">True</span>)</span><br><span class="line">[&lt;Stream: itag=<span class="string">"140"</span> mime_type=<span class="string">"audio/mp4"</span> abr=<span class="string">"128kbps"</span> acodec=<span class="string">"mp4a.40.2"</span> progressive=<span class="string">"False"</span> type=<span class="string">"audio"</span>&gt;,</span><br><span class="line">&lt;Stream: itag=<span class="string">"249"</span> mime_type=<span class="string">"audio/webm"</span> abr=<span class="string">"50kbps"</span> acodec=<span class="string">"opus"</span> progressive=<span class="string">"False"</span> type=<span class="string">"audio"</span>&gt;,</span><br><span class="line">&lt;Stream: itag=<span class="string">"250"</span> mime_type=<span class="string">"audio/webm"</span> abr=<span class="string">"70kbps"</span> acodec=<span class="string">"opus"</span> progressive=<span class="string">"False"</span> type=<span class="string">"audio"</span>&gt;,</span><br><span class="line">&lt;Stream: itag=<span class="string">"251"</span> mime_type=<span class="string">"audio/webm"</span> abr=<span class="string">"160kbps"</span> acodec=<span class="string">"opus"</span> progressive=<span class="string">"False"</span> type=<span class="string">"audio"</span>&gt;]</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>保留 mp4 后缀的视频：</p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>yt.streams.filter(file_extension=<span class="string">'mp4'</span>)</span><br><span class="line">[&lt;Stream: itag=<span class="string">"18"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"360p"</span> fps=<span class="string">"30fps"</span> vcodec=<span class="string">"avc1.42001E"</span> acodec=<span class="string">"mp4a.40.2"</span> progressive=<span class="string">"True"</span> type=<span class="string">"video"</span>&gt;,</span><br><span class="line">&lt;Stream: itag=<span class="string">"22"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"720p"</span> fps=<span class="string">"30fps"</span> vcodec=<span class="string">"avc1.64001F"</span> acodec=<span class="string">"mp4a.40.2"</span> progressive=<span class="string">"True"</span> type=<span class="string">"video"</span>&gt;,</span><br><span class="line">&lt;Stream: itag=<span class="string">"137"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"1080p"</span> fps=<span class="string">"30fps"</span> vcodec=<span class="string">"avc1.640028"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;,</span><br><span class="line">...</span><br><span class="line">&lt;Stream: itag=<span class="string">"394"</span> mime_type=<span class="string">"video/mp4"</span> res=<span class="string">"None"</span> fps=<span class="string">"30fps"</span> vcodec=<span class="string">"av01.0.00M.08"</span> progressive=<span class="string">"False"</span> type=<span class="string">"video"</span>&gt;,</span><br><span class="line">&lt;Stream: itag=<span class="string">"140"</span> mime_type=<span class="string">"audio/mp4"</span> abr=<span class="string">"128kbps"</span> acodec=<span class="string">"mp4a.40.2"</span> progressive=<span class="string">"False"</span> type=<span class="string">"audio"</span>&gt;]</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>比如获取字幕：</p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>yt = YouTube(<span class="string">'http://youtube.com/watch?v=2lAe1cqCOXo'</span>)</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>yt.captions</span><br><span class="line">&#123;<span class="string">'ar'</span>: &lt;Caption lang=<span class="string">"Arabic"</span> code=<span class="string">"ar"</span>&gt;, <span class="string">'zh-HK'</span>: &lt;Caption lang=<span class="string">"Chinese (Hong Kong)"</span> code=<span class="string">"zh-HK"</span>&gt;, <span class="string">'zh-TW'</span>: &lt;Caption lang=<span class="string">"Chinese (Taiwan)"</span> code=<span class="string">"zh-TW"</span>&gt;, ...</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里各国语言的字幕几乎都有。</p>
                  <p>另外还可以把字幕打印出来，比如输出 srt 格式：</p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="meta">&gt;&gt;&gt; </span>caption = yt.captions.get_by_language_code(<span class="string">'en'</span>)</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>print(caption.generate_srt_captions())</span><br><span class="line"><span class="number">1</span></span><br><span class="line">00:00:10,200 --&gt; 00:00:11,140</span><br><span class="line">K-pop!</span><br><span class="line"></span><br><span class="line"><span class="number">2</span></span><br><span class="line">00:00:13,400 --&gt; 00:00:16,200</span><br><span class="line">That <span class="keyword">is</span> so awkward to watch.</span><br><span class="line">...</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>对于播放列表的处理，比如新建 Playlist 对象，然后取出每一个视频的第一个视频流并下载：</p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="keyword">from</span> pytube <span class="keyword">import</span> Playlist</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>p = Playlist(<span class="string">'https://www.youtube.com/playlist?list=PLS1QulWo1RIaJECMeUT4LFwJ-ghgoSH6n'</span>)</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="keyword">for</span> video <span class="keyword">in</span> p.videos:</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>    video.streams.first().download()</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>另外还有一些异常处理机制：</p>
                  <figure class="highlight python">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="keyword">from</span> pytube <span class="keyword">import</span> Playlist, YouTube</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>playlist_url = <span class="string">'https://youtube.com/playlist?list=special_playlist_id'</span></span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span>p = Playlist(playlist_url)</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="keyword">for</span> url <span class="keyword">in</span> p.video_urls:</span><br><span class="line"><span class="meta">... </span>    <span class="keyword">try</span>:</span><br><span class="line"><span class="meta">... </span>        yt = YouTube(url)</span><br><span class="line"><span class="meta">... </span>    <span class="keyword">except</span> VideoUnavailable:</span><br><span class="line"><span class="meta">... </span>        print(<span class="string">f'Video <span class="subst">&#123;url&#125;</span> is unavaialable, skipping.'</span>)</span><br><span class="line"><span class="meta">... </span>    <span class="keyword">else</span>:</span><br><span class="line"><span class="meta">... </span>        print(<span class="string">f'Downloading video: <span class="subst">&#123;url&#125;</span>'</span>)</span><br><span class="line"><span class="meta">... </span>        yt.streams.first().download()</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>总之，使用这个库，我们不仅可以使用命令行方便地下载 Youtube 视频和播放列表，还可以使用代码灵活地控制，一举两得！</p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-02-26 15:37:07" itemprop="dateCreated datePublished" datetime="2021-02-26T15:37:07+08:00">2021-02-26</time>
                </span>
                <span id="/30008.html" class="post-meta-item leancloud_visitors" data-flag-title="介绍一个超强的 Youtube 下载工具 pytube" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>10k</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>10 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30007.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 个人记录 <i class="label-arrow"></i>
                  </a>
                  <a href="/30007.html" class="post-title-link" itemprop="url">今天，微软给所有员工加了五天年假</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>今天还是照常上班，和以往没有太多不同。</p>
                  <p>然而，办公室里面有位同事一句话惊动了周围所有同事——我们今年又多了五天假期？！</p>
                  <p>听罢，同事们像是刚中了彩票一样，一个个高兴得像个孩子，但还不知道具体咋回事。</p>
                  <p>：哪啊？哪说的啊？</p>
                  <p>：快看看邮件啊</p>
                  <p>：哪封邮件啊？</p>
                  <p>：就今天上午刚发的公司全员邮件啊！标题叫 Announcing Wellbeing Days</p>
                  <p>：好家伙，你不说我还真没注意</p>
                  <p>其实我也没注意，然后开始翻邮件，果不其然，找到了！</p>
                  <p>标题很明显了：</p>
                  <blockquote>
                    <p>Announcing Wellbeing Days</p>
                  </blockquote>
                  <p>具体的邮件内容不详细说了，总体意思就是说，现在全球新冠疫情严重，大家都面临非常多的压力，其中有一句关键的信息：</p>
                  <blockquote>
                    <p>Thus, I am excited to announce five new paid WellbeingDays to support you.</p>
                  </blockquote>
                  <p>是的，为此公司决定 2021 年给每个员工都加五天全薪“幸福关怀假”。</p>
                  <p>巨硬牛逼！</p>
                  <p>然后我又详细看了看，这个针对哪些员工呢？</p>
                  <blockquote>
                    <p>2021 年 9 月 30 之前入职的员工都可以获得这五天假期，2021 年 9 月 30 到 12 月 1 日入职的员工，可以获得三天假期。</p>
                  </blockquote>
                  <p>今年我的年假已经变成：</p>
                  <blockquote>
                    <p>去年留到今年的还有 13 天，今年 15 天还没用，再加上 5 天，33 天年假了。</p>
                  </blockquote>
                  <p>简直是良心了，这下我终于也体验到了一会“别人公司”的幸福感。</p>
                  <p>想来的，简历可以砸过来了。</p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-02-19 15:37:07" itemprop="dateCreated datePublished" datetime="2021-02-19T15:37:07+08:00">2021-02-19</time>
                </span>
                <span id="/30007.html" class="post-meta-item leancloud_visitors" data-flag-title="今天，微软给所有员工加了五天年假" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>552</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>1 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30017.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 技术杂谈 <i class="label-arrow"></i>
                  </a>
                  <a href="/30017.html" class="post-title-link" itemprop="url">介绍一个软件，一秒打开 GitHub</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>给大家介绍一个非常实用的工具，有了它，我们可以在几秒之内用 VS Code 打开 GitHub 上的任意一个 Repo，无需 Clone，速度飞快。</p>
                  <p>用法也十分简单而且好记，下面给大家介绍下。</p>
                  <h2 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h2>
                  <p>比如这里是 Scrapy 的仓库：<a href="https://github.com/scrapy/scrapy，用" target="_blank" rel="noopener">https://github.com/scrapy/scrapy，用</a> GitHub 打开是这样的：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/2tmq8.png" alt="GitHub仓库"></p>
                  <p>看代码的时候我们可能需要一个个点进去，速度慢而且感觉不太方便。</p>
                  <p>为此大家可能安装了一些 Chrome 插件，比如比较火的是 Octotree，安装之后效果是这样的：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/io5m1.png" alt="Octotree效果"></p>
                  <p>安装这个插件之后，在网页左侧会出现一个文件树方便我们快速定位文件。然鹅，个人感觉总不是真正想要的那种味道。</p>
                  <p>现在好了。</p>
                  <p>这时候，我们只需要在网址 github 后面加上 <code>1s</code>，变成：<a href="https://github1s.com/scrapy/scrapy" target="_blank" rel="noopener">https://github1s.com/scrapy/scrapy</a></p>
                  <p><img src="https://qiniu.cuiqingcai.com/whtf1.png" alt=""></p>
                  <p>没错，就是这么简单好记。</p>
                  <p>访问之后，就可以看到这样的页面：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/qq5bh.png" alt=""></p>
                  <p>是的没错，这就在浏览器中打开了一个在线版的 VS Code，并打开了 Scrapy 的源代码，看代码就非常方便了。</p>
                  <p>无需克隆，无需任何配置，打开飞速，代码高亮！</p>
                  <p>一些快捷键也是和 VS Code 一样的，比如 Cmd/Ctrl + P，就可以快速找到一个文件：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/kec7w.png" alt=""></p>
                  <p>Cmd/Ctrl + F 搜索：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/bxaj7.png" alt=""></p>
                  <p>不过我试了一下全局搜索貌似只能限制在一个文件内，不知道是哪里设置的问题。</p>
                  <p>有的朋友可能会问，代码能修改吗？</p>
                  <p>答案是不能，代码都是以只读模式打开的，也就是我们只能看，没法改。不过这也合情合理，毕竟任意 Repo 都能打开，改了又存到哪里呢？</p>
                  <h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2>
                  <p>另外有的朋友可能好奇这个的实现原理是怎样的，我扒了一下源码，看到作者是这么介绍的：</p>
                  <blockquote>
                    <p>Github1s is based on <a href="https://github.com/microsoft/vscode/tree/1.52.1" target="_blank" rel="noopener">VS Code 1.52.1</a> now. VS Code can be built for a browser version officially. I also used the code and got inspired by <a href="https://github.com/cdr/code-server" target="_blank" rel="noopener">Code Server</a>.</p>
                    <p>Thanks to the very powerful and flexible extensibility of VS Code, we can easily implement a VS Code extension that provides the custom File IO ability using <a href="https://code.visualstudio.com/api/references/vscode-api#FileSystemProvider" target="_blank" rel="noopener">FileSystemProvider API</a>. There is an official demo named <a href="https://github.com/microsoft/vscode-web-playground" target="_blank" rel="noopener">vscode-web-playground</a> which shows how it is used.</p>
                    <p>On the other hand, GitHub provides the powerful <a href="https://docs.github.com/en/rest" target="_blank" rel="noopener">REST API</a> that can be used for a variety of tasks which includes reading directories and files for sure.</p>
                    <p>According to the above, obviously, the core concept of GitHub1s is to implement a VS Code Extension (includes FileSystemProvider) using GitHub REST API.</p>
                    <p><em>We may switch to the GitHub GraphQL API for more friendly user experience in the future, thanks to @xcv58 and @kanhegaonkarsaurabh. See details at <a href="https://github.com/conwnet/github1s/issues/12" target="_blank" rel="noopener">Issue 12</a>.</em></p>
                    <p>GitHub1s is a purely static web app (because it really doesn’t need a backend service, does it?). So we just deploy it on <a href="https://pages.github.com/" target="_blank" rel="noopener">GitHub Pages</a> now (the <code>gh-pages</code> branch of this repository), and it is free. The service of GitHub1s could be reliable (GitHub is very reliable) because nobody needs to pay the web hosting bills.</p>
                  </blockquote>
                  <p>总的来说，GitHub1s 这个仓库是基于 VS Code 构建的，灵感来源于 Code Server 这个 Repo，地址为：<a href="https://github.com/cdr/code-server，这个就是一个" target="_blank" rel="noopener">https://github.com/cdr/code-server，这个就是一个</a> Online 版的 VS Code。</p>
                  <p>那作者基于这个做了什么事呢？</p>
                  <p>他基于 VS Code 提供的 FileSystemProvider API 对接了 GitHub 的 REST API 实现了这些功能。其中前者是 VS Code 提供的，可以提供文件读写操作，当然读写在线文件也是没问题的了；而后者是 GitHub 提供的，通过 REST API 可以获取 Repo 的文件夹或者某个文件。</p>
                  <p>如此，GitHub1s 就诞生了。</p>
                  <p>知道了原理之后，我们也可以自己把 GitHub1s 代码下载下来，改写一下，扩展一些功能：比如解除只读限制，保存的时候直接存储到自己的 Repo 等。</p>
                  <p>具体的修改和开发流程可以参见：<a href="https://github.com/conwnet/github1s/blob/master/docs/guide.md#development" target="_blank" rel="noopener">https://github.com/conwnet/github1s/blob/master/docs/guide.md#development</a></p>
                  <h2 id="访问频率限制"><a href="#访问频率限制" class="headerlink" title="访问频率限制"></a>访问频率限制</h2>
                  <p>另外作者也提到了一点：</p>
                  <blockquote>
                    <p>For unauthenticated requests, the rate limit allows for up to 60 requests per hour. Unauthenticated requests are associated with the originating IP address, and not the user making requests.</p>
                  </blockquote>
                  <p>对于未授权的请求，API 的请求频率是有限制的，每个 IP 每个小时访问限制是 60 次，所以用着用着就容易超限制了，可能就打不开文件了。</p>
                  <p>这里的频率限制我解读下，有朋友可能好奇，因为这个网站是 github1s.com 来 serve 的，所以请求是不是都是 github1s.com 这个服务器发出来的呢？所以不同的人其实都是用的一个 IP？</p>
                  <p>其实不是的，我观察了一下网络请求，是当前网页直接请求了 GitHub 的 API 实现的，所以 IP 就是我们自己客户端的真实 IP，网络请求如下所示：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/ni9hr.png" alt=""></p>
                  <p>但是请求 GitHub 的 API 没有跨域问题吗？</p>
                  <p>没有，这是因为 GitHub API 设置了解除跨域访问，Response Headers 里面可以看到：</p>
                  <figure class="highlight ada">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">access</span>-control-allow-origin: *</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>所以任何网站都可以直接请求 GitHub 的 API。</p>
                  <p>OK，说回解除频率限制的问题：</p>
                  <blockquote>
                    <p>For API requests using Basic Authentication or OAuth, you can make up to 5,000 requests per hour.</p>
                  </blockquote>
                  <p>这里说如果登录了，每小时就可以提高到 5000 次请求了。</p>
                  <p>怎么设置呢？</p>
                  <p>可以在 github1s.com 打开侧栏的 OAuth 设置，如图所示：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/4yowy.png" alt="image-20210215212607189"></p>
                  <p>然后点击 Generate New OAuth Token，跳到自己的 GitHub Setting 页面，生成一个 Token 就好了，如图所示：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/hubcs.png" alt=""></p>
                  <p>好了之后贴回来就 OK 了，这样频率限制就解除了，爽歪歪。</p>
                  <h2 id="彩蛋"><a href="#彩蛋" class="headerlink" title="彩蛋"></a>彩蛋</h2>
                  <p>另外我还发现了有一个配套的 Chrome 插件，也叫 GitHub1s，大家可以自己搜索安装：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/i3txz.png" alt=""></p>
                  <p>安装完成之后，每个 GitHub Repo 都会自动多出一个绿色按钮，如图所示：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/kxt5x.png" alt=""></p>
                  <p>点击之后就直接跳转到刚才所说的 github1s.com 打开这个 Repo 了，简直不要太方便！</p>
                  <p>另外还有另外一个开发者写的插件，效果是这样的：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/cfswy.png" alt=""></p>
                  <p>感觉这个还是挺小巧精致的，可以来这里下载：<a href="https://github.com/2293736867/Github1sExtension" target="_blank" rel="noopener">https://github.com/2293736867/Github1sExtension</a></p>
                  <h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2>
                  <p>好了，以后看 GitHub 代码就有新神器了，大家快去试试看吧～</p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-02-16 15:37:07" itemprop="dateCreated datePublished" datetime="2021-02-16T15:37:07+08:00">2021-02-16</time>
                </span>
                <span id="/30017.html" class="post-meta-item leancloud_visitors" data-flag-title="介绍一个软件，一秒打开 GitHub" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>3.1k</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>3 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30010.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 技术杂谈 <i class="label-arrow"></i>
                  </a>
                  <a href="/30010.html" class="post-title-link" itemprop="url">Gitalk 评论登录 403 问题解决</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>事情是这样的，最近发现我的博客 cuiqingcai.com 的评论功能出现了问题，登录功能不好用了。经过一番排查，我找到了一些解决方案，在这里记录一下问题排查过程。</p>
                  <p>另外这个排查过程中可以总结出一些思路，大家如果碰到类似的问题，也可以按照类似的思路来排查。</p>
                  <p>友情提示：大家一定要读到最后或者直接拉到最后，最后内容的可能对你更有价值。</p>
                  <h2 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h2>
                  <p>我的博客最近刚换上了 hexo 框架，于是评论功能就换成了 Gitalk。但最近发现登录功能不好用了，点击使用 GitHub 登录总是失败。</p>
                  <p>就点击这个按钮的时候，始终登录不上去：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/n79m6.png" alt="image-20210212223917778"></p>
                  <p>于是我就想着手解决一下这个问题。</p>
                  <h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2>
                  <p>这里就记录一下我在排查过程中碰到的一些坑和解决思路。</p>
                  <p>首先，登录失败的问题，第一时间应该去排查的就是网络请求，打开控制台，查看 Network 面板，出现类似的结果：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/4d8sw.png" alt="image-20210212224407613"></p>
                  <p>网络请求直接 403 了，拿不到 token 了，于是就登录不上了。</p>
                  <p>观察下，这个链接 cors-anywhere 似乎是用来解决跨域限制的，后面还跟了一个 GitHub 的 Access Token 获取地址，那没跑了，前面这个就是一个反向代理，后面是真实的请求 URL。</p>
                  <p>OK，看着这个也没啥思路啊，然后接着怎么办？</p>
                  <p>那就接着去搜这个 cors-anywhere.herokuapp.com，因为 herokuapp 很眼熟嘛，就是一个公用的网址 Host 平台，类似于 AWS、Azure 之类的，那么前面这个可能包含某些信息。万一是开源的那就好办了。</p>
                  <p>接着搜，cors-anywhere，然后就搜到了这个：<a href="https://github.com/Rob--W/cors-anywhere" target="_blank" rel="noopener">https://github.com/Rob--W/cors-anywhere</a></p>
                  <p>介绍如下：</p>
                  <blockquote>
                    <p><strong>CORS Anywhere</strong> is a NodeJS proxy which adds CORS headers to the proxied request.</p>
                    <p>The url to proxy is literally taken from the path, validated and proxied. The protocol part of the proxied URI is optional, and defaults to “http”. If port 443 is specified, the protocol defaults to “https”.</p>
                    <p>This package does not put any restrictions on the http methods or headers, except for cookies. Requesting <a href="http://www.w3.org/TR/cors/#user-credentials" target="_blank" rel="noopener">user credentials</a> is disallowed. The app can be configured to require a header for proxying a request, for example to avoid a direct visit from the browser.</p>
                  </blockquote>
                  <p>真是一个开源框架，和我猜的一样，就是一个解决跨域问题而生的反向代理。</p>
                  <p>然后我就在它的 README 中看到了这个：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/e9xla.png" alt="image-20210212224946845"></p>
                  <p>好家伙，这不就是我刚才用到的链接吗？</p>
                  <p>那肯定是这个玩意出了什么毛病。</p>
                  <p>咋看呢？这个果断就是找 Issue 了：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/yyu6t.png" alt="image-20210212225114466"></p>
                  <p>一看，太明显了：</p>
                  <blockquote>
                    <p>PSA: Public demo server (cors-anywhere.herokuapp.com) will be very limited by January 2021, 31st</p>
                  </blockquote>
                  <p>意思就是从今年 1.31 开始这个网站的访问会受限，点进去看看：</p>
                  <blockquote>
                    <p>The demo server of CORS Anywhere (cors-anywhere.herokuapp.com) is meant to be a demo of this project. But abuse has become so common that the platform where the demo is hosted (Heroku) has asked me to shut down the server, despite efforts to counter the abuse (rate limits in <a href="https://github.com/Rob--W/cors-anywhere/issues/45" target="_blank" rel="noopener">#45</a> and <a href="https://github.com/Rob--W/cors-anywhere/issues/164" target="_blank" rel="noopener">#164</a>, and blocking other forms of requests). Downtime becomes increasingly frequent (e.g. recently <a href="https://github.com/Rob--W/cors-anywhere/issues/300" target="_blank" rel="noopener">#300</a>, <a href="https://github.com/Rob--W/cors-anywhere/issues/299" target="_blank" rel="noopener">#299</a>, <a href="https://github.com/Rob--W/cors-anywhere/issues/295" target="_blank" rel="noopener">#295</a>, <a href="https://github.com/Rob--W/cors-anywhere/issues/294" target="_blank" rel="noopener">#294</a>, <a href="https://github.com/Rob--W/cors-anywhere/issues/287" target="_blank" rel="noopener">#287</a>) due to abuse and its popularity.</p>
                    <p>To counter this, I will make the following changes:</p>
                    <ol>
                      <li>The rate limit will decrease from 200 (<a href="https://github.com/Rob--W/cors-anywhere/issues/164" target="_blank" rel="noopener">#164</a>) per hour to 50 per hour.</li>
                      <li>By January 31st, 2021, cors-anywhere.herokuapp.com will stop serving as an open proxy.</li>
                      <li>From February 1st. 2021, cors-anywhere.herokuapp.com will only serve requests after the visitor has completed a challenge: The user (developer) must visit a page at cors-anywhere.herokuapp.com to temporarily unlock the demo for their browser. This allows developers to try out the functionality, to help with deciding on self-hosting or looking for alternatives.</li>
                    </ol>
                  </blockquote>
                  <p>好吧，意思就是说这个网站本来是演示用的，但是现在已经被滥用了，然后从 1.31 开始用户手动必须手动先访问这个网站获取临时的访问权限，然后才能使用。另外推荐开发者自己来维护一个网站。</p>
                  <p>接着下面的评论第一个就更滑稽了：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/7d55t.png" alt="image-20210212225414735"></p>
                  <p>这个人直接艾特了 gitalk，哈哈哈，因为 Gitalk 就如刚才所说的那样，也用了这个。</p>
                  <p>那就顺便去 Gitalk <a href="https://github.com/gitalk/gitalk，逛一下" target="_blank" rel="noopener">https://github.com/gitalk/gitalk，逛一下</a> issue，看看是不是也有人遇到了同样的问题，果不其然了：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/s7bn5.png" alt="image-20210212225919986"></p>
                  <p>最近几个 issue 都是关于 403 的，真热闹。</p>
                  <p>点进去看看，有个大收获，里面有个好心人说：</p>
                  <blockquote>
                    <p>这次直接去嫖了一个CORS proxy,把gitalk.js的6794行改为 proxy: ‘<a href="https://netnr-proxy.cloudno.de/https://github.com/login/oauth/access_token" target="_blank" rel="noopener">https://netnr-proxy.cloudno.de/https://github.com/login/oauth/access_token</a>‘, 就可以了。具体能用多久我也没普，且用且珍惜。</p>
                  </blockquote>
                  <p>真是得来全不费功夫，本来还想着自己部署着，这次那就换了就行了。</p>
                  <p>然而，这样不行，得需要改 gitalk.js 的源码，并不太好吧。</p>
                  <p>好，这时候就遇到了一个问题，要修改某些开源软件的源码应该怎么办？</p>
                  <p>首选的思路当然不是硬改，改了之后还要自己 host 一个新的 js 文件，那显然是很费精力的。</p>
                  <p>其实一半程序在编写的时候应该是预留一些接口和配置的，我们应该能很轻易地通过某些配置就能实现某些配置的复写。</p>
                  <p>那就接着看看吧，既然要改，那就得先看看 Gitalk 是怎么用的吧。</p>
                  <p>看文档，Gitalk 调用方式如下：</p>
                  <figure class="highlight javascript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">const</span> gitalk = <span class="keyword">new</span> Gitalk(&#123;</span><br><span class="line">  clientID: <span class="string">'GitHub Application Client ID'</span>,</span><br><span class="line">  clientSecret: <span class="string">'GitHub Application Client Secret'</span>,</span><br><span class="line">  repo: <span class="string">'GitHub repo'</span>,      <span class="comment">// The repository of store comments,</span></span><br><span class="line">  owner: <span class="string">'GitHub repo owner'</span>,</span><br><span class="line">  admin: [<span class="string">'GitHub repo owner and collaborators, only these guys can initialize github issues'</span>],</span><br><span class="line">  id: location.pathname,      <span class="comment">// Ensure uniqueness and length less than 50</span></span><br><span class="line">  distractionFreeMode: <span class="literal">false</span>  <span class="comment">// Facebook-like distraction free mode</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">gitalk.render(<span class="string">'gitalk-container'</span>)</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>看来这个在声明的时候是有参数的，那刚才 URL 配置没看到在哪里配啊，既然如此，那就看看 Gitalk 这个对象支持多少参数吧。</p>
                  <p>接着就去找 Gitalk 的构造参数说明，找到这么一个：</p>
                  <ul>
                    <li>proxy：<code>String</code></li>
                  </ul>
                  <p>Default: <code>https://cors-anywhere.herokuapp.com/https://github.com/login/oauth/access_token</code>.</p>
                  <p>果然找到了，所以这里如果我们要修改，那就改 proxy 参数就行了，初始化 Gitalk 的时候复写掉 proxy 就行。</p>
                  <p>OK，基本思路有了，那我怎么改到我的源码里呢？</p>
                  <p>我的博客是基于 Hexo 的 Next 主题的，根据经验，Gitalk 是 Next 主题自带的，所以 Gitalk 的声明应该就在 Next 主题源码里面。</p>
                  <p>那怎么找呢？</p>
                  <p>这时候就需要借助于一些搜索技巧了，搜什么？既然要用 Gitalk，那一定有刚才初始化的调用，那就搜 Gitalk 这个关键字就行了。另外还需要缩小一下搜索范围。</p>
                  <p>于是我就把范围限定到了 next 主题目录，搜索 Gitalk。</p>
                  <p><img src="https://qiniu.cuiqingcai.com/ey8tq.png" alt="image-20210212230931998"></p>
                  <p>简直不要太舒服，一搜就有了，文件是 themes/next/layout/_third-party/comments/gitalk.swig。</p>
                  <p>这里我们只需要把 proxy 参数加上不就行了，值是什么呢？仿照写就行了，配置风格保持统一，那就加一条：</p>
                  <figure class="highlight groovy">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="string">proxy       :</span> <span class="string">'&#123;&#123; theme.gitalk.proxy &#125;&#125;'</span>,</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>OK，那这个配置的值很明显是主题配置文件，那就把配置文件里面加上 proxy 这个参数就好了。</p>
                  <p>找到 themes/next/_config.yml，添加行：</p>
                  <figure class="highlight awk">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">proxy: https:<span class="regexp">//</span>netnr-proxy.cloudno.de<span class="regexp">/https:/</span><span class="regexp">/github.com/</span>login<span class="regexp">/oauth/</span>access_token</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>结果如下：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/nnb1f.png" alt="image-20210212231224403"></p>
                  <p>好了，大公告成！</p>
                  <p>重新部署 Hexo，现在评论又能重新使用了，问题就解决了！</p>
                  <p>测试地址：<a href="https://cuiqingcai.com/message/，大家来给我留言吧～">https://cuiqingcai.com/message/，大家来给我留言吧～</a></p>
                  <p>好了，这就是我排查问题的整个过程，做一下记录。</p>
                  <h2 id="经验"><a href="#经验" class="headerlink" title="经验"></a>经验</h2>
                  <p>另外，其实这篇文章的用意不仅仅是单纯解决这个问题，因为这个问题大家可能并没有遇到过，因此这个解决方案仅仅是给极少数遇到这个问题的朋友提供的。</p>
                  <p>但是，这并不代表这篇文章没有价值，因为其中有的思路是通用的，在这里稍微做一下总结，希望对大家有帮助：</p>
                  <ul>
                    <li>当遇到网页功能异常的时候，排查问题就主要看两个——控制台、网络请求，这里面往往能找到主要问题。</li>
                    <li>结合一些基本知识进行合理的推断，比如刚才我就推断了 cors- anywhere 的作用并结合 herokuapp 推断这个可能还会是个公用的服务。</li>
                    <li>当碰到没有思路或者不确定的时候，去谷歌它！不要百度，另外还可以在 GitHub 或者 Gitee 上搜。</li>
                    <li>如果找到对应的 GitHub 仓库，Issue 区往往能找到一些有效答案，比如刚才我就在 Issue 区找到了一个可替代的 cors 网站。</li>
                    <li>修改代码功能的时候要想着尽量复写，也就是 overwrite，而不是直接改，前者更具有灵活性，而且某些情况下会省去一些麻烦。</li>
                    <li>复写的时候去找一些参数配置，比如找一些初始化参数、默认参数配置，看看能否实现改写的需求。</li>
                    <li>找不到入口的时候善用全局搜索功能，比如刚才 Gitalk 找哪里调用的时候，就直接全局搜索。</li>
                    <li>根据功能限制某些搜索范围，比如刚才我就知道 Gitalk 这个功能是 Next 主题提供的，所以我就直接限制搜索范围是 Next 主题的源码。</li>
                    <li>以上步骤多尝试，熟能生巧。</li>
                  </ul>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-02-12 10:16:18" itemprop="dateCreated datePublished" datetime="2021-02-12T10:16:18+08:00">2021-02-12</time>
                </span>
                <span id="/30010.html" class="post-meta-item leancloud_visitors" data-flag-title="Gitalk 评论登录 403 问题解决" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>4.8k</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>4 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30018.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 技术杂谈 <i class="label-arrow"></i>
                  </a>
                  <a href="/30018.html" class="post-title-link" itemprop="url">Vue.js 的 prop 如何实现双向绑定</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>最近遇到了一个问题，就是 Vue.js 中的 prop 如何实现双向绑定比较好。</p>
                  <p>之前我都是把 prop 传递到子组件，然后子组件里面直接把 prop 直接改了，这样虽然能把结果反映到父组件，但并不是一个很好的解决方案。</p>
                  <p>比如我就经常遇到这样的 Warning：</p>
                  <blockquote>
                    <p>Avoid mutating a prop directly since the value will be overwritten…</p>
                  </blockquote>
                  <p>实际上，用事件传递的方式把修改从子组件传到父组件是比较不错的方式，这就需要子组件 $emit 一个事件，然后父组件监听这个事件，然后将接收到的值修改就好了。</p>
                  <p>官方文档的说明如下：</p>
                  <blockquote>
                    <p>在有些情况下，我们可能需要对一个 prop 进行“双向绑定”。不幸的是，真正的双向绑定会带来维护上的问题，因为子组件可以变更父组件，且在父组件和子组件都没有明显的变更来源。</p>
                    <p>这也是为什么我们推荐以 <code>update:myPropName</code> 的模式触发事件取而代之。举个例子，在一个包含 <code>title</code> prop 的假设的组件中，我们可以用以下方法表达对其赋新值的意图：</p>
                    <figure class="highlight javascript">
                      <table>
                        <tr>
                          <td class="gutter">
                            <pre><span class="line">1</span><br></pre>
                          </td>
                          <td class="code">
                            <pre><span class="line"><span class="keyword">this</span>.$emit(<span class="string">'update:title'</span>, newTitle)</span><br></pre>
                          </td>
                        </tr>
                      </table>
                    </figure>
                  </blockquote>
                  <p>所以这里推荐的就是使用 <code>update:propName</code> 来实现。</p>
                  <p>这样的话，父组件原生的写法如下：</p>
                  <figure class="highlight html">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="tag">&lt;<span class="name">text-document</span></span></span><br><span class="line"><span class="tag">  <span class="attr">v-bind:title</span>=<span class="string">"doc.title"</span></span></span><br><span class="line"><span class="tag">  <span class="attr">v-on:update:title</span>=<span class="string">"doc.title = $event"</span></span></span><br><span class="line"><span class="tag">&gt;</span><span class="tag">&lt;/<span class="name">text-document</span>&gt;</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里 prop 的名字叫做 title，子组件需要接收到这个值，然后各种操作进行修改都没关系。</p>
                  <p>比如子组件可以这么写：</p>
                  <figure class="highlight plain">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;el-input v-model&#x3D;&quot;titleData&quot;&gt;&lt;&#x2F;el-input&gt;</span><br><span class="line">&lt;&#x2F;template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &quot;Child&quot;,</span><br><span class="line">  props: &#123;</span><br><span class="line">    title: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &quot;&quot;,</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      titleData: this.title</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  watch: &#123;</span><br><span class="line">    titleData: &#123;</span><br><span class="line">      handler(val) &#123;</span><br><span class="line">        this.$emit(&#39;update:title&#39;, val)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;&#x2F;script&gt;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这样当 titleData 更新的时候，父组件的 title 就更新了。</p>
                  <p>这时候父组件可以简写为：</p>
                  <figure class="highlight html">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="tag">&lt;<span class="name">text-document</span> <span class="attr">v-bind:title.sync</span>=<span class="string">"doc.title"</span>&gt;</span><span class="tag">&lt;/<span class="name">text-document</span>&gt;</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <blockquote>
                    <p>注意带有 <code>.sync</code> 修饰符的 <code>v-bind</code> <strong>不能</strong>和表达式一起使用 (例如 <code>v-bind:title.sync=”doc.title + ‘!’”</code> 是无效的)。取而代之的是，你只能提供你想要绑定的 property 名，类似 <code>v-model</code>。</p>
                  </blockquote>
                  <p>另外当我们用一个对象同时设置多个 prop 的时候，也可以将这个 <code>.sync</code> 修饰符和 <code>v-bind</code> 配合使用：</p>
                  <figure class="highlight html">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="tag">&lt;<span class="name">text-document</span> <span class="attr">v-bind.sync</span>=<span class="string">"doc"</span>&gt;</span><span class="tag">&lt;/<span class="name">text-document</span>&gt;</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这样会把 <code>doc</code> 对象中的每一个 property (如 <code>title</code>) 都作为一个独立的 prop 传进去，然后各自添加用于更新的 <code>v-on</code> 监听器。</p>
                  <blockquote>
                    <p>将 <code>v-bind.sync</code> 用在一个字面量的对象上，例如 <code>v-bind.sync=”{ title: doc.title }”</code>，是无法正常工作的，因为在解析一个像这样的复杂表达式的时候，有很多边缘情况需要考虑。</p>
                  </blockquote>
                  <p>以上，完毕。</p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-02-11 20:16:18" itemprop="dateCreated datePublished" datetime="2021-02-11T20:16:18+08:00">2021-02-11</time>
                </span>
                <span id="/30018.html" class="post-meta-item leancloud_visitors" data-flag-title="Vue.js 的 prop 如何实现双向绑定" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>1.7k</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>2 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30005.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 技术杂谈 <i class="label-arrow"></i>
                  </a>
                  <a href="/30005.html" class="post-title-link" itemprop="url">怎样让你的GitHub全绿</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>写这篇文章的缘由来自看到了知乎上的一个问题——在 GitHub 上保持 365 天全绿是一种怎样的体验？</p>
                  <h2 id="解释"><a href="#解释" class="headerlink" title="解释"></a>解释</h2>
                  <p>大家可能有的不明白啥意思啊，这个绿指的是就是 GitHub 的 Contribution，如果你每天都提交代码到 GitHub，至少一次 commit，那么 GitHub 就会在你当天对应的 Contribution 格子上点上绿色，比如我的就是这样子：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/bir3j.png" alt=""></p>
                  <p>因为我经常在 GitHub 上提交代码，所以我的 Contribution 页面就显示为绿色，commit 多的就深，少的就浅，灰色的就是当然没有任何代码提交的。</p>
                  <p>所以这个问题问的就是，每天都在 GitHub 上提交代码是什么体验，也就是 365 天每天一天不落地撸代码是什么体验？</p>
                  <p>然后有一个回答看得我笑出声：</p>
                  <blockquote>
                    <p>曾经保持了200多天全绿，但是冷落了女朋友，一直绿到现在。</p>
                  </blockquote>
                  <p>原回答如下：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/v3th3.png" alt=""></p>
                  <p>这哥们真的是太秀了，秀到我实在忍不住给他默默点了个赞…</p>
                  <p>不过咱们还是言归正传啊，说回这个问题。</p>
                  <p>其实说实话真的保持 365 天全绿真的是一件很难的事情，每周都会有周末吧，周末得陪女朋友吧？什么，你没有女朋友，那忽略这一条。</p>
                  <p>那即使没有女朋友，一年不得有几天是过年过节的，还撸啥代码啊？即使不是逢年过节，那也总有几天状态不好或者生病的吧，强如铁人那坚持 365 天天撸代码也是够神的。</p>
                  <p>不过我还真见过几个，实打实的大神，比如 Taylor Otweel，PHP Laravel 框架的开发者，一年 8000 多次 commit，他的 Contribution 是这样的：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/c8w1x.png" alt=""></p>
                  <p>这个是真的强，而且人家撸的代码质量肯定也高啊，不像我们可能改了点 README 啥的。</p>
                  <p>但强如 Taylor Otweel，你也能看到有些天是没有贡献的，毕竟人家周末可能就真的不撸代码或者有其他的安排。</p>
                  <p>那怎么才能做到 365 天全绿呢？</p>
                  <p>既然人不行，那就靠机器人吧。</p>
                  <p>GitHub 不是这两年出了个 GitHub Actions 的功能吗？这就是 CI 嘛，借助于它，我们想做到 GitHub 365 天全绿，就轻而易举了。</p>
                  <p>到底怎么做？难不难。</p>
                  <p>不难，可能只需要两分钟就搞定了。</p>
                  <p>想不想知道怎么做的？想知道的接着往下看。</p>
                  <h2 id="方案"><a href="#方案" class="headerlink" title="方案"></a>方案</h2>
                  <p>这里介绍一个 GitHub 的库，地址为：<a href="https://github.com/justjavac/auto-green，借助它，咔咔几步就能搞定了。" target="_blank" rel="noopener">https://github.com/justjavac/auto-green，借助它，咔咔几步就能搞定了。</a></p>
                  <p>先说步骤。</p>
                  <p>首先打开这个仓库，点 Use this template，注意千万不要点 Fork，不然是不生效的，如图所示：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/xlcq9.png" alt=""></p>
                  <p>点了之后就是提示你用这个 Template 创建一个自己的 Git 残酷，这时候就会让你填写的的仓库名称，比如我就创建了一个名字叫做 AutoGreen 的仓库，如图所示：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/a83or.png" alt=""></p>
                  <p>至此，已经成功了一半了。</p>
                  <p>现在你会观察到，在 Actions 这个选项卡自动执行了一个任务。啪！很快啊，执行完了：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/44c26.png" alt=""></p>
                  <p>执行完了你会发现这个仓库多了一次 commit，是来自 justjavac 的一次 commit：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/1s33b.png" alt=""></p>
                  <p>点进去看看，commit 的信息还叫 “a commit a day keeps your girlfriend away”，啥意思？</p>
                  <p>跟代码做好朋友，永远没有女朋友？？？Oh，No，不是这样的！</p>
                  <p>commit 如图所示：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/0cnts.png" alt=""></p>
                  <p>神奇的是这次 commit 还没有任何 file change，还是个空的 commit。</p>
                  <p>行了，不管这么多了。</p>
                  <p>到现在就结束了吗？GitHub 以后就会天天绿了吗，当然不会绿啊，为啥啊？</p>
                  <p>扒一扒源码看一下，打开 <code>.github/workflows/ci.yml</code> 文件，结果如下：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/4v7aa.png" alt="">代码：</p>
                  <figure class="highlight yaml">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="attr">name:</span> <span class="string">ci</span></span><br><span class="line"></span><br><span class="line"><span class="attr">on:</span></span><br><span class="line">  <span class="attr">push:</span></span><br><span class="line">    <span class="attr">branches:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">master</span></span><br><span class="line">  <span class="attr">schedule:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">cron:</span> <span class="string">"0 0 * * *"</span></span><br><span class="line"></span><br><span class="line"><span class="attr">jobs:</span></span><br><span class="line">  <span class="attr">autogreen:</span></span><br><span class="line">    <span class="attr">runs-on:</span> <span class="string">ubuntu-latest</span></span><br><span class="line">    <span class="attr">steps:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Clone</span> <span class="string">repository</span></span><br><span class="line">        <span class="attr">uses:</span> <span class="string">actions/checkout@v2</span></span><br><span class="line"></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Auto</span> <span class="string">green</span></span><br><span class="line">        <span class="attr">run:</span> <span class="string">|</span></span><br><span class="line">          <span class="string">git</span> <span class="string">config</span> <span class="string">--local</span> <span class="string">user.email</span> <span class="string">"justjavac@gmail.com"</span></span><br><span class="line">          <span class="string">git</span> <span class="string">config</span> <span class="string">--local</span> <span class="string">user.name</span> <span class="string">"迷渡"</span></span><br><span class="line">          <span class="string">git</span> <span class="string">remote</span> <span class="string">set-url</span> <span class="string">origin</span> <span class="string">https://$&#123;&#123;</span> <span class="string">github.actor</span> <span class="string">&#125;&#125;:$&#123;&#123;</span> <span class="string">secrets.GITHUB_TOKEN</span> <span class="string">&#125;&#125;@github.com/$&#123;&#123;</span> <span class="string">github.repository</span> <span class="string">&#125;&#125;</span></span><br><span class="line">          <span class="string">git</span> <span class="string">pull</span> <span class="string">--rebase</span></span><br><span class="line">          <span class="string">git</span> <span class="string">commit</span> <span class="string">--allow-empty</span> <span class="string">-m</span> <span class="string">"a commit a day keeps your girlfriend away"</span></span><br><span class="line">          <span class="string">git</span> <span class="string">push</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>看看这个文件，意思就是每天执行一下下面的这几行代码，比如 git 的 config、commit、push 等，就相当于模拟了一次提交。</p>
                  <p>其中有几行代码比较有意思：</p>
                  <figure class="highlight dsconfig">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="string">git </span><span class="string">remote </span><span class="built_in">set-url</span> <span class="string">origin </span><span class="string">https:</span>//$&#123;&#123; <span class="string">github.</span><span class="string">actor </span>&#125;&#125;:$&#123;&#123; <span class="string">secrets.</span><span class="string">GITHUB_TOKEN </span>&#125;&#125;@<span class="string">github.</span><span class="string">com/</span>$&#123;&#123; <span class="string">github.</span><span class="string">repository </span>&#125;&#125;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里就是指定远程仓库等地址，这里有几个占位符，github 的 actor 和 repository 对象，其实这些我们不用管，在运行的时候会被自动赋值为当前仓库的信息，另外还有 GITHUB_TOKEN 也是在该任务运行的时候自动添加的。</p>
                  <p>另外还有一行代码：</p>
                  <figure class="highlight pgsql">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">git <span class="keyword">commit</span> <span class="comment">--allow-empty -m "a commit a day keeps your girlfriend away"</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里的 commit 操作加上了一个 <code>--allow-empty</code> 选项，意思就是允许空的提交，这也就解释了上文空提交的缘由了。</p>
                  <p>OK，但这里我们再回过头来看看配置就知道为啥不算我们的提交了：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/zv2tf.png" alt=""></p>
                  <p>因为这里配置的是原作者的 GitHub 邮箱，所以这次提交当然就会算作原作者的了。</p>
                  <p>那怎么才能让我们的绿呢？那把邮箱改成我们自己的就好了，比如我的就修改为了这样子：</p>
                  <figure class="highlight">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="attribute">name</span>: ci</span><br><span class="line"></span><br><span class="line"><span class="attribute">on:</span></span><br><span class="line">  push:</span><br><span class="line">    branches:</span><br><span class="line">      - master</span><br><span class="line">  schedule:</span><br><span class="line">    - cron: "0 0 * * *"</span><br><span class="line"></span><br><span class="line"><span class="attribute">jobs:</span></span><br><span class="line">  autogreen:</span><br><span class="line">    runs-on: ubuntu-latest</span><br><span class="line">    steps:</span><br><span class="line">      - name: Clone repository</span><br><span class="line">        uses: actions/checkout@v2</span><br><span class="line"></span><br><span class="line">      - name: Auto green</span><br><span class="line">        run: |</span><br><span class="line">          git config --local user.email "cqc@cuiqingcai.com"</span><br><span class="line">          git config --local user.name "Germey"</span><br><span class="line">          git remote set-url origin https://$&#123;&#123; github.actor &#125;&#125;:$&#123;&#123; secrets.GITHUB_TOKEN &#125;&#125;@github.com/$&#123;&#123; github.repository &#125;&#125;</span><br><span class="line">          git pull --rebase</span><br><span class="line">          git commit --allow-empty -m "a commit a day keeps your girlfriend away"</span><br><span class="line">          git push</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>直接在 GitHub 网页上点击修改，修改好了保存就行了。</p>
                  <p>修改完了之后我们就自动有了一次 commit，接着 Actions 还会自动触发一次 commit，最后结果如图所示：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/a5wv5.png" alt=""></p>
                  <p>可以看到，最后这次 commit 已经变成我自己了。</p>
                  <p>以后，我每天都可以自动绿了。</p>
                  <p>（这话怎么听着这么奇怪？</p>
                  <h2 id="福利"><a href="#福利" class="headerlink" title="福利"></a>福利</h2>
                  <p>最后，原作者还预留了一个定时任务，可以使得你想绿就绿，不仅可以让你每天都绿，还能让你每小时都绿，每分钟都能绿。</p>
                  <p>想绿就绿，其乐无穷。</p>
                  <p>绿的方式很简单，套用原作者的介绍了，修改 yml 文件的定时配置就好了：</p>
                  <p>计划任务语法有 5 个字段，中间用空格分隔，每个字段代表一个时间单位。</p>
                  <figure class="highlight plain">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">┌───────────── 分钟 (0 - 59)</span><br><span class="line">│ ┌───────────── 小时 (0 - 23)</span><br><span class="line">│ │ ┌───────────── 日 (1 - 31)</span><br><span class="line">│ │ │ ┌───────────── 月 (1 - 12 或 JAN-DEC)</span><br><span class="line">│ │ │ │ ┌───────────── 星期 (0 - 6 或 SUN-SAT)</span><br><span class="line">│ │ │ │ │</span><br><span class="line">│ │ │ │ │</span><br><span class="line">│ │ │ │ │</span><br><span class="line">* * * * *</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>每个时间字段的含义：</p>
                  <div class="table-container">
                    <table>
                      <thead>
                        <tr>
                          <th>符号</th>
                          <th>描述</th>
                          <th>举例</th>
                        </tr>
                      </thead>
                      <tbody>
                        <tr>
                          <td><code>*</code></td>
                          <td>任意值</td>
                          <td><code>* * * * *</code> 每天每小时每分钟</td>
                        </tr>
                        <tr>
                          <td><code>,</code></td>
                          <td>值分隔符</td>
                          <td><code>1,3,4,7 * * * *</code> 每小时的 1 3 4 7 分钟</td>
                        </tr>
                        <tr>
                          <td><code>-</code></td>
                          <td>范围</td>
                          <td><code>1-6 * * * *</code> 每小时的 1-6 分钟</td>
                        </tr>
                        <tr>
                          <td><code>/</code></td>
                          <td>每</td>
                          <td><code>*/15 * * * *</code> 每隔 15 分钟</td>
                        </tr>
                      </tbody>
                    </table>
                  </div>
                  <p>比如修改为 <code>0 * * * *</code> ，你就能做到每小时都绿了，修改为 <code>* * * * *</code> 你就能每分钟都绿了，真舒服啊！</p>
                  <p><strong>注</strong>：由于 GitHub Actions 的限制，如果设置为 <code>* * * * *</code> 实际的执行频率为每 5 分执行一次，也就是每 5 分钟绿一次，也还不错嘛～</p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-02-11 20:16:18" itemprop="dateCreated datePublished" datetime="2021-02-11T20:16:18+08:00">2021-02-11</time>
                </span>
                <span id="/30005.html" class="post-meta-item leancloud_visitors" data-flag-title="怎样让你的GitHub全绿" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>3.7k</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>3 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30016.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 技术杂谈 <i class="label-arrow"></i>
                  </a>
                  <a href="/30016.html" class="post-title-link" itemprop="url">各种变量格式你真的都清楚吗？</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>大家想必听说过一些变量命名格式，比如大驼峰式、小驼峰式，其他的你还知道什么？</p>
                  <p>今天看文档的时候，提到了一个 kebab case，这个你知道是什么命名格式吗？不知道的接着往下看。</p>
                  <p>这篇文章我们把所有变量命名格式梳理下。</p>
                  <h2 id="Lower-Camel-Case"><a href="#Lower-Camel-Case" class="headerlink" title="Lower Camel Case"></a>Lower Camel Case</h2>
                  <p>又名：小驼峰式</p>
                  <p>特征：第一个单词首字母小写，后续单词首字母大写。</p>
                  <p>例如：firstName、lastName</p>
                  <h2 id="Upper-Camel-Case"><a href="#Upper-Camel-Case" class="headerlink" title="Upper Camel Case"></a>Upper Camel Case</h2>
                  <p>又名：大驼峰式、Pascal Case</p>
                  <p>特征：每个单词的首字母都大写。</p>
                  <p>例如：FirstName、LastName</p>
                  <h2 id="Snake-Case"><a href="#Snake-Case" class="headerlink" title="Snake Case"></a>Snake Case</h2>
                  <p>特征：每个单词小写，单词之间用下划线连接。</p>
                  <p>例如：first_name、last_name</p>
                  <h2 id="Kebab-Case"><a href="#Kebab-Case" class="headerlink" title="Kebab Case"></a>Kebab Case</h2>
                  <p>又名：Spinal Case、Train Case、Lisp Case</p>
                  <p>特征：每个单词小写，单词之间用中划线连接。</p>
                  <p>例如：first-name、last-name</p>
                  <h2 id="Studly-Case"><a href="#Studly-Case" class="headerlink" title="Studly Case"></a>Studly Case</h2>
                  <p>特征：混合大小写，对大写字母的使用没有<a href="https://en.wikipedia.org/wiki/Semantics" target="_blank" rel="noopener">语义</a>或<a href="https://en.wikipedia.org/wiki/Syntax" target="_blank" rel="noopener">语法</a>意义。有时只有<a href="https://en.wikipedia.org/wiki/Vowel" target="_blank" rel="noopener">元音</a>是大写的，其他时候大写和小写是交替的，但通常只是随机的。这个名字来自讽刺或讽刺意味，它是作者试图传达自己的冷静的一种尝试。它也可以用来模拟营销人员在命名计算机软件包时违反标准英语案例惯例的行为，即使在没有技术要求的情况下也是如此。</p>
                  <p>例如：tHeqUicKBrOWnFoXJUmpsoVeRThElAzydOG</p>
                  <h2 id="参考来源"><a href="#参考来源" class="headerlink" title="参考来源"></a>参考来源</h2>
                  <ul>
                    <li><a href="https://en.wikipedia.org/wiki/Letter_case" target="_blank" rel="noopener">https://en.wikipedia.org/wiki/Letter_case</a></li>
                  </ul>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-02-11 10:16:18" itemprop="dateCreated datePublished" datetime="2021-02-11T10:16:18+08:00">2021-02-11</time>
                </span>
                <span id="/30016.html" class="post-meta-item leancloud_visitors" data-flag-title="各种变量格式你真的都清楚吗？" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>618</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>1 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30008.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 技术杂谈 <i class="label-arrow"></i>
                  </a>
                  <a href="/30008.html" class="post-title-link" itemprop="url">Base64 的图片如何完美复制到系统粘贴板</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2>
                  <p>最近开发过程中遇到了一个小知识点，这里有一张 Base64 编码的图片，我想要把它复制到系统的粘贴板中，这个该怎么解决？</p>
                  <p>比如这里有一张图：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/9wixm.png" alt="404"></p>
                  <p>我可以通过 Base64 转换工具转换为 Base64 编码，转换网址为 <a href="https://www.base64-image.de/，转换结果如下：" target="_blank" rel="noopener">https://www.base64-image.de/，转换结果如下：</a></p>
                  <p><img src="https://qiniu.cuiqingcai.com/soqwi.png" alt=""></p>
                  <p>图片就是类似 <code>...</code> 这样的编码。</p>
                  <p>问：现在有一张这样格式的图片，怎么把它复制到系统粘贴板中？</p>
                  <h2 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h2>
                  <p>首先这里需要用到一个 JavaScript 库，叫做 clipboard-polyfill，这个库的 npm 包地址为： <a href="https://www.npmjs.com/package/clipboard-polyfill，" target="_blank" rel="noopener">https://www.npmjs.com/package/clipboard-polyfill，</a></p>
                  <p>看库的介绍有个关键的部分：</p>
                  <figure class="highlight javascript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> clipboard <span class="keyword">from</span> <span class="string">"clipboard-polyfill"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">handler</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">"Previous clipboard contents:"</span>, <span class="keyword">await</span> clipboard.read());</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> item = <span class="keyword">new</span> clipboard.ClipboardItem(&#123;</span><br><span class="line">    <span class="string">"text/html"</span>: <span class="keyword">new</span> Blob(</span><br><span class="line">      [<span class="string">"&lt;i&gt;Markup&lt;/i&gt; &lt;b&gt;text&lt;/b&gt;. Paste me into a rich text editor."</span>],</span><br><span class="line">      &#123; <span class="attr">type</span>: <span class="string">"text/html"</span> &#125;</span><br><span class="line">    ),</span><br><span class="line">    <span class="string">"text/plain"</span>: <span class="keyword">new</span> Blob(</span><br><span class="line">      [<span class="string">"Fallback markup text. Paste me into a rich text editor."</span>],</span><br><span class="line">      &#123; <span class="attr">type</span>: <span class="string">"text/plain"</span> &#125;</span><br><span class="line">    ),</span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="keyword">await</span> clipboard.write([item]);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">window</span>.addEventListener(<span class="string">"DOMContentLoaded"</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> button = <span class="built_in">document</span>.createElement(<span class="string">"button"</span>);</span><br><span class="line">  button.textContent = <span class="string">"Copy"</span>;</span><br><span class="line">  button.addEventListener(<span class="string">"click"</span>, handler);</span><br><span class="line">  <span class="built_in">document</span>.body.appendChild(button);</span><br><span class="line">&#125;);</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里可以创建一个 ClipboardItem 对象，并传入对应的 Blob 内容，同时指定对应的 content-type 即可。</p>
                  <p>OK，那这里就需要一个关键部分，那就是如何把 Base64 编码的图片转化为 Blob。</p>
                  <p>一般来说，Base64 编码的图片的开头是 <code>data:image/jpg;base64,</code>，后面跟的就是 Base64 真实编码。</p>
                  <p>这里提供一个方法，可以将 Base64 编码转化为 Blob，代码如下：</p>
                  <figure class="highlight javascript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">b64toBlob</span>(<span class="params">b64Data, contentType = null, sliceSize = null</span>) </span>&#123;</span><br><span class="line">  contentType = contentType || <span class="string">'image/png'</span></span><br><span class="line">  sliceSize = sliceSize || <span class="number">512</span></span><br><span class="line">  <span class="keyword">let</span> byteCharacters = atob(b64Data)</span><br><span class="line">  <span class="keyword">let</span> byteArrays = []</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> offset = <span class="number">0</span>; offset &lt; byteCharacters.length; offset += sliceSize) &#123;</span><br><span class="line">    <span class="keyword">let</span> slice = byteCharacters.slice(offset, offset + sliceSize)</span><br><span class="line">    <span class="keyword">let</span> byteNumbers = <span class="keyword">new</span> <span class="built_in">Array</span>(slice.length);</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; slice.length; i++) &#123;</span><br><span class="line">      byteNumbers[i] = slice.charCodeAt(i)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">var</span> byteArray = <span class="keyword">new</span> <span class="built_in">Uint8Array</span>(byteNumbers)</span><br><span class="line">    byteArrays.push(byteArray)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> Blob(byteArrays, &#123;<span class="attr">type</span>: contentType&#125;)</span><br><span class="line">&#125;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里其实就是将 Base64 编码先转化为了 Uint8Array，然后再将其转化为 Blob，并指定 contentType 即可。</p>
                  <p>接下来复制到粘贴板就很简单了，调用最上面的方法声明 ClipboardItem 对象即可：</p>
                  <figure class="highlight javascript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">clip</span>(<span class="params">b64Data</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> item = <span class="keyword">new</span> clipboard.ClipboardItem(&#123;</span><br><span class="line">    <span class="string">"image/png"</span>: <span class="keyword">this</span>.b64toBlob(b64Data.replace(<span class="string">'data:image/jpg;base64,'</span>, <span class="string">''</span>), <span class="string">'image/png'</span>, <span class="number">512</span>)</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里 contentType 指定为了 <code>image/png</code>。</p>
                  <p>至此，clip 方法传入 Base64 编码的图片即可复制到系统粘贴板了，亲测可以在 Windows、Mac 上生效。</p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-02-10 10:16:18" itemprop="dateCreated datePublished" datetime="2021-02-10T10:16:18+08:00">2021-02-10</time>
                </span>
                <span id="/30008.html" class="post-meta-item leancloud_visitors" data-flag-title="Base64 的图片如何完美复制到系统粘贴板" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>2.2k</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>2 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30004.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 技术杂谈 <i class="label-arrow"></i>
                  </a>
                  <a href="/30004.html" class="post-title-link" itemprop="url">腾讯云TKE里面获取客户端真实IP</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>最近服务器都迁移到腾讯云 TKE 了，就是腾讯云 Kubernetes 服务，然后最近有个需求是获取客户端真实 IP。</p>
                  <p>我的情况：</p>
                  <ul>
                    <li>服务用 Django 写的，通过 HTTP 请求头获取真实 IP</li>
                    <li>Django 通过 uwsgi 运行，并通过 Nginx 转发出去</li>
                    <li>Ingress 使用的 Nginx Ingress，而不是 TKE Ingress</li>
                  </ul>
                  <p>下面说下几个关键配置：</p>
                  <h2 id="Django-中获取-IP"><a href="#Django-中获取-IP" class="headerlink" title="Django 中获取 IP"></a>Django 中获取 IP</h2>
                  <p>获取方式如下：</p>
                  <figure class="highlight routeros">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">def get_client_ip(request):</span><br><span class="line">    x_forwarded_for = request.META.<span class="builtin-name">get</span>(<span class="string">'HTTP_X_FORWARDED_FOR'</span>)</span><br><span class="line">    <span class="keyword">if</span> x_forwarded_for:</span><br><span class="line">       <span class="built_in"> ip </span>= x_forwarded_for.split(<span class="string">','</span>)[0]</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">       <span class="built_in"> ip </span>= request.META.<span class="builtin-name">get</span>(<span class="string">'REMOTE_ADDR'</span>)</span><br><span class="line">    return ip</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <h2 id="uwsgi-配置"><a href="#uwsgi-配置" class="headerlink" title="uwsgi 配置"></a>uwsgi 配置</h2>
                  <p>uwsgi.ini 配置如下：</p>
                  <figure class="highlight ini">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="section">[uwsgi]</span></span><br><span class="line"><span class="attr">module</span> = core.wsgi</span><br><span class="line"><span class="attr">master</span> = <span class="literal">true</span></span><br><span class="line"><span class="attr">processes</span> = <span class="number">1</span></span><br><span class="line"><span class="attr">vacuum</span> = <span class="literal">true</span></span><br><span class="line"><span class="attr">static-map</span> = /static=/app/app/static</span><br><span class="line"><span class="attr">http</span> = <span class="number">127.0</span>.<span class="number">0.1</span>:<span class="number">8000</span></span><br><span class="line"><span class="attr">log-master</span> = <span class="literal">true</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <h2 id="Nginx-配置"><a href="#Nginx-配置" class="headerlink" title="Nginx 配置"></a>Nginx 配置</h2>
                  <p>Nginx 需要转发 uwsgi 出去，并且加上三个关键请求头：</p>
                  <figure class="highlight nginx">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">    <span class="attribute">listen</span>       <span class="number">7777</span>;</span><br><span class="line">    <span class="attribute">server_name</span>  localhost;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">location</span> / &#123;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Real-IP <span class="variable">$remote_addr</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-For <span class="variable">$proxy_add_x_forwarded_for</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> Host <span class="variable">$http_host</span>;</span><br><span class="line">        <span class="attribute">proxy_pass</span> http://127.0.0.1:8000;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <h2 id="Supervisor-配置"><a href="#Supervisor-配置" class="headerlink" title="Supervisor 配置"></a>Supervisor 配置</h2>
                  <p>Supervisor 需要启动 Uwsgi 和 Nginx：</p>
                  <figure class="highlight ini">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="section">[supervisord]</span></span><br><span class="line"><span class="attr">nodaemon</span>=<span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="section">[program:uwsgi]</span></span><br><span class="line"><span class="attr">command</span>=uwsgi --ini /app/uwsgi.ini</span><br><span class="line"><span class="attr">stdout_logfile</span>=/dev/stdout</span><br><span class="line"><span class="attr">stdout_logfile_maxbytes</span>=<span class="number">0</span></span><br><span class="line"><span class="attr">stderr_logfile</span>=/dev/stderr</span><br><span class="line"><span class="attr">stderr_logfile_maxbytes</span>=<span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="section">[program:nginx]</span></span><br><span class="line"><span class="attr">command</span>=/usr/sbin/nginx -g <span class="string">"pid /run/nginx/nginx.pid; daemon off;"</span></span><br><span class="line"><span class="attr">stdout_logfile</span>=/dev/stdout</span><br><span class="line"><span class="attr">stdout_logfile_maxbytes</span>=<span class="number">0</span></span><br><span class="line"><span class="attr">stderr_logfile</span>=/dev/stderr</span><br><span class="line"><span class="attr">stderr_logfile_maxbytes</span>=<span class="number">0</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <h2 id="Dockerfile-配置"><a href="#Dockerfile-配置" class="headerlink" title="Dockerfile 配置"></a>Dockerfile 配置</h2>
                  <p>Dockkerfile 里面指定启动的命令为 supervisor：</p>
                  <figure class="highlight dockerfile">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">FROM</span> python:<span class="number">3.7</span>-alpine</span><br><span class="line"><span class="keyword">ENV</span> PYTHONUNBUFFERED <span class="number">1</span></span><br><span class="line"><span class="keyword">WORKDIR</span><span class="bash"> /app</span></span><br><span class="line"><span class="keyword">COPY</span><span class="bash"> requirements.txt .</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> apk update &amp;&amp; apk add \</span></span><br><span class="line"><span class="bash">        libuuid \</span></span><br><span class="line"><span class="bash">        gcc \</span></span><br><span class="line"><span class="bash">        nginx \</span></span><br><span class="line"><span class="bash">        supervisor \</span></span><br><span class="line"><span class="bash">        libc-dev \</span></span><br><span class="line"><span class="bash">        linux-headers \</span></span><br><span class="line"><span class="bash">        postgresql-libs \</span></span><br><span class="line"><span class="bash">        postgresql-dev \</span></span><br><span class="line"><span class="bash">    &amp;&amp; pip install pip -U \</span></span><br><span class="line"><span class="bash">    &amp;&amp; pip install -r requirements.txt</span></span><br><span class="line"><span class="keyword">COPY</span><span class="bash"> . /app</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> mkdir -p /run/nginx</span></span><br><span class="line"><span class="keyword">COPY</span><span class="bash"> nginx.conf /etc/nginx/conf.d/default.conf</span></span><br><span class="line"><span class="keyword">COPY</span><span class="bash"> supervisord.conf /etc/supervisord.conf</span></span><br><span class="line"><span class="keyword">CMD</span><span class="bash"> [<span class="string">"/usr/bin/supervisord"</span>, <span class="string">"-c"</span>, <span class="string">"/etc/supervisord.conf"</span>]</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <h3 id="TKE-配置"><a href="#TKE-配置" class="headerlink" title="TKE 配置"></a>TKE 配置</h3>
                  <p>这里参考来源为：<a href="https://cloud.tencent.com/document/product/457/48949" target="_blank" rel="noopener">https://cloud.tencent.com/document/product/457/48949</a></p>
                  <p>最关键的就是：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/whe5t.png" alt=""></p>
                  <p>这里我需要修改 Service 的负载均衡：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/4k05y.png" alt=""></p>
                  <p>修改 externalTrafficPolicy 为 Local 即可：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/77mvl.png" alt=""></p>
                  <p>大功告成，后面 IP 就能成功获取到了。</p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-01-03 17:57:38" itemprop="dateCreated datePublished" datetime="2021-01-03T17:57:38+08:00">2021-01-03</time>
                </span>
                <span id="/30004.html" class="post-meta-item leancloud_visitors" data-flag-title="腾讯云TKE里面获取客户端真实IP" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>1.8k</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>2 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30003.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> 技术杂谈 <i class="label-arrow"></i>
                  </a>
                  <a href="/30003.html" class="post-title-link" itemprop="url">uwsgi将日志输出到控制台的方法</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>之前配置 uwsgi 的时候，配完了之后 Python 的日志就输出不出来了，其实可以在 uwsgi.ini 里面加一个日志配置就行了，很简单：</p>
                  <figure class="highlight crmsh">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">log-<span class="keyword">master</span> <span class="title">= true</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>示例配置如下：</p>
                  <figure class="highlight ini">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="section">[uwsgi]</span></span><br><span class="line"><span class="attr">module</span> = core.wsgi</span><br><span class="line"><span class="attr">master</span> = <span class="literal">true</span></span><br><span class="line"><span class="attr">processes</span> = <span class="number">1</span></span><br><span class="line"><span class="attr">vacuum</span> = <span class="literal">true</span></span><br><span class="line"><span class="attr">static-map</span> = /static=/app/app/static</span><br><span class="line"><span class="attr">http</span> = <span class="number">127.0</span>.<span class="number">0.1</span>:<span class="number">8000</span></span><br><span class="line"><span class="attr">log-master</span> = <span class="literal">true</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>加上这句之后，日志就可以顺利输出到控制台了。</p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-01-03 17:29:43" itemprop="dateCreated datePublished" datetime="2021-01-03T17:29:43+08:00">2021-01-03</time>
                </span>
                <span id="/30003.html" class="post-meta-item leancloud_visitors" data-flag-title="uwsgi将日志输出到控制台的方法" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>243</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>1 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30002.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a href="/30002.html" class="post-title-link" itemprop="url">加湿器还有这么多讲究</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>说到加湿器，那就不得不先提一下空气净化器。</p>
                  <p>之前其实我家里是没有空气净化器的，最近刚搬新住处就入手了一个，因为我想打造一套全新的小米之家，哈哈哈。</p>
                  <p>这个空气净化器用和没用给我的感觉区别不大，因为我确实感觉不到室内空气好一点或者坏一点有啥区别。但是记得在我刚打开空气净化器的一瞬间，上面的空气质量指数显示为 180 多（实际上这个是说的 PM 2.5 的指数），重度污染！我直接好家伙，难道我没用空气净化器的二十多年一直都呼吸的是重度污染的空气吗？心中不由倒吸一口凉气。净化器开了一会，那个质量指数慢慢降低，最后一直降到 10 以下，我心里也慢慢舒服多了，这时候我就感觉自己处在一个洁净的环境里面。所以，虽然我自己并不能感受出来空气变好了，但是心里是舒服的、安心的。</p>
                  <p>那为什么又扯到加湿器呢？</p>
                  <p>这是因为当我在开着空气净化器的时候，和往常一样打开我的加湿器…这时候，空气净化器显示的空气质量指数直接爆表了，直接 200 以上，当场就把我吓坏了。我当时就跟我老婆说，老婆我们这个加湿器有问题啊，它加湿后的水雾怎么控制质量这么差，肯定对身体有害。说完了之后我就去搜新的加湿器去了。因为最近我在搞米家智能家居，所以第一个搜的就是小米的加湿器，搜到这么一款：</p>
                  <p><img src="https://qiniu.cuiqingcai.com/7zaiu.png" alt=""></p>
                  <p>OK，除菌加湿器，很好，有了这个除菌功能，加湿的空气应该不会那么差了。当时我那款「美的」的加湿器是没有这个功能的，所以我就又跟老婆说，老婆我搜到这个小米的加湿器是有除菌功能的，我买了这个肯定就没事了，于是我成功说服了我老婆，于是我的米家智能家居又新增了一员。</p>
                  <p>然而，等到货之后我灌上水重新打开，情况居然跟我想的不一样！空气净化器依然非常高，直逼 200，这是怎么回事？难道这个除菌功能一点用都没有？</p>
                  <p>抱着好奇又震惊的心情，我就去网上查，原来，这个和水有关系。空气指数上升的原因可以简单这么解释：这么因为我用的是自来水，而自来水含有氯、重金属等杂质，我买的加湿器又属于超声波式加湿器，它的原理是利用超声波将水打散成直径只有 1-5 微米的细小颗粒，然后利用风动装置将这些小颗粒吹到空气中，所以自来水中的杂质也就跟着进入空气中了，这就导致了空气净化器指数急剧上升，污染空气，长期这样下去对人体并不好。</p>
                  <p>看到这里，那就牵扯到了几个概念，一个是水，一个是加湿器，这两者的不同组合可能产生不同的结果，下面且听我一一道来。</p>
                  <h2 id="水"><a href="#水" class="headerlink" title="水"></a>水</h2>
                  <p>首先说水啊，其实我们平常见到的水有很多种，名字也不同，目前常见的水可以分为这么几种类别：自来水、白开水、纯净水、矿泉水、天然水、蒸馏水，咋这么多？听着都懵啊，下面来解释下。</p>
                  <h3 id="自来水"><a href="#自来水" class="headerlink" title="自来水"></a>自来水</h3>
                  <p>这个大家都知道了，水龙头里面直接放出来的水就是自来水，它是经过自来水厂加工、消毒之后生产出来的复合国家饮用水标准的工人们生产生活用的水，消毒的时候，里面含有一些微生物（如大肠杆菌）、重金属、有机污染物、泥沙等物质，另外由于自来水厂喜欢用氯气消毒，所以自来水里面还含有一些氯离子，总之这些都是对人体健康不利的。看到这里不要害怕，那就不能喝了吗？没关系，把水烧开了就行了。</p>
                  <h3 id="白开水"><a href="#白开水" class="headerlink" title="白开水"></a>白开水</h3>
                  <p>白开水就是把自然水直接烧开得到的水，因为刚才也说了，自来水里面含有各种对人体有害的物质，把水烧开后，大部分细菌病毒都会被杀死，一些氯也会被分解掉，另外钙、镁和一些重金属离子也会在烧开的过程中形成沉淀，也就是我们通常说的水垢。不过金属离子是不能完全沉淀的，所以水中还会有溶解有少量的重金属离子，所以并不是完完全全是干净的，但基本问题不大。另外白开水其实口感非常不好，喝起来很涩，反正我是完全喝不惯白开水的味道。</p>
                  <h3 id="矿泉水"><a href="#矿泉水" class="headerlink" title="矿泉水"></a>矿泉水</h3>
                  <p>大家肯定听说过矿泉水，但你平时喝的还真不一定是矿泉水，目前比较常见的矿泉水有百岁山、恒大冰泉等，它是是天然含有矿物质离子或盐或硫化物或二氧化碳气体等物质的水，矿泉水对水源地要求很高，不同水源地的矿物质含量也不同，比如百岁山的河寨山水源说是富含了偏硅酸锂、锶、钙、钾等多种有益于人体健康的微量元素，是为数不多的优质水源，当然依云也是。</p>
                  <h3 id="纯净水"><a href="#纯净水" class="headerlink" title="纯净水"></a>纯净水</h3>
                  <p>纯净水就是水里不含任何其他物质，只有水分子的水，没有任何矿物质。它是经过一些离子交换、反渗透、蒸馏等工艺制成的，过滤掉了细菌、病毒等有害物质，而且几乎不含任何矿物质，水的硬度也很低，用它烧水也不会形成水垢。纯净水可以有两种获取方式，一种就是家里装净水器，出来的都是纯净水。另外就是直接购买，比如怡宝就是纯净水。</p>
                  <h3 id="天然水"><a href="#天然水" class="headerlink" title="天然水"></a>天然水</h3>
                  <p>天然水，最常见的就是农夫山泉，它的标识叫做饮用天然水，为啥他不标识天然矿泉水呢？它其实和矿泉水几乎差不多，但是其中有益的元素含量并不能达到天然矿泉水的要求。百岁山的水源相对农夫山泉更好一些，农夫山泉的水源有好几个基地，一般来说千岛湖的最好喝，带有一点甘甜的味道。不过不仔细对比，这个和矿泉水大查不差，反正都含有一些钙、镁、钾等矿物质。</p>
                  <h3 id="蒸馏水"><a href="#蒸馏水" class="headerlink" title="蒸馏水"></a>蒸馏水</h3>
                  <p>蒸馏水相比大家在学习化学等时候听说过，其实就是把水烧开，把水蒸气收集下来，然后再把水蒸气液化，分离出来的水就是纯水了，和纯净水一样也是不含矿物质的。由于工艺复杂，制造设备昂贵，所以蒸馏水一般在实验室比较常用，家庭基本上没有喝的，当然要买也能买到，比如屈臣氏的瓶装蒸馏水，价格不菲。</p>
                  <p>好，说完了以上的水，那哪种水适合放在加湿器（目前指的是超声波加湿器）里面不会引起空气指数升高呢？答案是纯净水和蒸馏水，其他的都不行。纯净水和蒸馏水加上之后，我的空气净化器指数基本没有变化，保持超绿色状态，舒服了。</p>
                  <p>另外平时喝的话，矿泉水、纯净水、天然水、白开水其实都行，虽然说矿泉水相比纯净水多了一些对人体有益的矿物质，但人体矿物质的摄入也不一定是靠水嘛，所以基本没有什么影响。</p>
                  <p>好，说完了水，那就得再说说加湿器了，这个其实也是有讲究的。</p>
                  <h2 id="加湿器"><a href="#加湿器" class="headerlink" title="加湿器"></a>加湿器</h2>
                  <p>市面上的加湿器主要分为两种，一种是超声波式加湿器，一种是冷蒸发式加湿器。</p>
                  <h3 id="超声波式加湿器"><a href="#超声波式加湿器" class="headerlink" title="超声波式加湿器"></a>超声波式加湿器</h3>
                  <p>大部分人家里的加湿器可能都是一二三百块钱的吧，加湿的过程中你还会看到白雾对不对？没错，这种加湿器就是超声波式加湿器，这种加湿器刚才也说了，利用高效的超声波振动将水打散成直径只有1-5微米的细小颗粒，再利用风动装置，将这些小颗粒吹到空气中，这种加湿器具有加湿速度快耗电量小、使用寿命长的优点，而且价格相对比较便宜，但存在不足之处在于对水要求高。</p>
                  <p><img src="https://qiniu.cuiqingcai.com/nq0t8.jpg" alt=""></p>
                  <h3 id="冷蒸发式加湿器"><a href="#冷蒸发式加湿器" class="headerlink" title="冷蒸发式加湿器"></a>冷蒸发式加湿器</h3>
                  <p>这种加湿器和超声波最大的区别就是加湿过程看不见水雾，它的原理就是通过循环风将液态水变成气态水，其实这种加湿器的加湿效果和超声波式相比并不占优势，不过加湿过程中，水是真正变成水蒸气而进入空气中的，所以水中的一些物质并不会进入到空气中，所以这种加湿器我们可以放心使用自来水，而不会引起空气净化器指数上升。不过这种加湿器价格都挺贵的，比超声波式加湿器贵了两三倍不止。</p>
                  <p>所以呢，到这里，基本就通透了吧，我用的加湿器就是第一种，这种加湿器就必须得用纯净水或者蒸馏水才能保证空气净化器不会爆表。如果加湿器是第二种，那随便用什么水都没啥关系了。</p>
                  <p>另外友情提醒，如果你的加湿器是第一种，请不要再用自来水了，对身体健康不利，还是改用纯净水吧，或者直接换个蒸发式加湿器也可以的。</p>
                  <p>所以说，这一番下来，学到还真不少，水和加湿器原来还有这么多讲究，生活真是处处皆学问啊。</p>
                  <h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2>
                  <p>想知道农夫山泉 景田百岁山和怡宝味道的差别? - 徐野的回答 - 知乎 <a href="https://www.zhihu.com/question/29367546/answer/109448432" target="_blank" rel="noopener">https://www.zhihu.com/question/29367546/answer/109448432</a></p>
                  <p>白开水、纯净水、矿泉水和蒸馏水哪个最适合做长期饮用水？ - 安吉尔的回答 - 知乎 <a href="https://www.zhihu.com/question/20418550/answer/1271349511" target="_blank" rel="noopener">https://www.zhihu.com/question/20418550/answer/1271349511</a></p>
                  <p>你的加湿器到底该加什么水？今天让你秒懂！<a href="http://jd.zol.com.cn/734/7346674.html" target="_blank" rel="noopener">http://jd.zol.com.cn/734/7346674.html</a></p>
                  <p>怎样选购加湿器？ - 老爸评测的回答 - 知乎 <a href="https://www.zhihu.com/question/22406803/answer/555850897" target="_blank" rel="noopener">https://www.zhihu.com/question/22406803/answer/555850897</a></p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2021-01-02 22:43:03" itemprop="dateCreated datePublished" datetime="2021-01-02T22:43:03+08:00">2021-01-02</time>
                </span>
                <span id="/30002.html" class="post-meta-item leancloud_visitors" data-flag-title="加湿器还有这么多讲究" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>3.2k</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>3 分钟</span>
                </span>
              </div>
            </article>
            <article itemscope itemtype="http://schema.org/Article" class="post-block index" lang="zh-CN">
              <link itemprop="mainEntityOfPage" href="https://cuiqingcai.com/30001.html">
              <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
                <meta itemprop="image" content="/images/avatar.png">
                <meta itemprop="name" content="崔庆才">
                <meta itemprop="description" content="崔庆才的个人站点，记录生活的瞬间，分享学习的心得。">
              </span>
              <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
                <meta itemprop="name" content="静觅">
              </span>
              <header class="post-header">
                <h2 class="post-title" itemprop="name headline">
                  <a class="label"> TypeScript <i class="label-arrow"></i>
                  </a>
                  <a href="/30001.html" class="post-title-link" itemprop="url">TypeScript教程二之接口</a>
                </h2>
              </header>
              <div class="post-body" itemprop="articleBody">
                <div class="thumb">
                  <img itemprop="contentUrl" class="random">
                </div>
                <div class="excerpt">
                  <p>
                  <p>上一节学习了 TypeScript 的基本类型，本节再来学习下接口 Interfaces 的使用。</p>
                  <p>TypeScript 的一个重要的特性就是帮助检查参数的字段是否是合法的，比如检查某个参数包含字段 foo，且类型需要是 number 类型，否则就会报错。通过接口，即 Interface 我们可以方便地实现这个操作。</p>
                  <h2 id="第一个-Interface"><a href="#第一个-Interface" class="headerlink" title="第一个 Interface"></a>第一个 Interface</h2>
                  <p>最简单的实现方式参考下面的例子：</p>
                  <figure class="highlight typescript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">printLabel</span>(<span class="params">labeledObj: &#123; label: <span class="built_in">string</span> &#125;</span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(labeledObj.label);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> myObj = &#123; size: <span class="number">10</span>, label: <span class="string">"Size 10 Object"</span> &#125;;</span><br><span class="line">printLabel(myObj);</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>在这里我们声明了一个方法，叫做 printLabel，它接收一个参数叫做 labeledObj，在 labeledObj 后面声明了该参数需要的字段和类型，这里它需要一个字段 label，且类型必须要是 string 类型。在调用时，我们传入了一个 Object，它包含了两个字段，一个是 size，类型为 number，另一个是 label，类型为 string。这里值得注意的是传入的参数是比声明的参数多了一个字段 size 的，但是这并没有关系，编译器只检查传入的参数是否至少存在所需要的属性，对于多余的属性是不关心的。</p>
                  <p>运行结果如下：</p>
                  <figure class="highlight markdown">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">[<span class="symbol">LOG</span>]: <span class="link">"Size 10 Object"</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>如果此时我们将 label 属性的类型修改为 number：</p>
                  <figure class="highlight typescript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">printLabel</span>(<span class="params">labeledObj: &#123; label: <span class="built_in">number</span> &#125;</span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(labeledObj.label);</span><br><span class="line">&#125;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>则会出现如下报错：</p>
                  <figure class="highlight routeros">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">Argument of<span class="built_in"> type </span><span class="string">'&#123; size: number; label: string; &#125;'</span> is <span class="keyword">not</span> assignable <span class="keyword">to</span> parameter of<span class="built_in"> type </span><span class="string">'&#123; label: number; &#125;'</span>. Types of property <span class="string">'label'</span> are incompatible.<span class="built_in"> Type </span><span class="string">'string'</span> is <span class="keyword">not</span> assignable <span class="keyword">to</span><span class="built_in"> type </span><span class="string">'number'</span>.</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里就提示 label 属性只能传入 number 类型，而不能是 string 类型。</p>
                  <p>但上面这个写法其实很不友好，如果属性比较多，那这个声明会非常复杂，而且不同方法如果都用到这个参数，难道还把它的声明都重复声明一遍？这也太不好了吧。</p>
                  <p>所以，为了更方便地实现声明，这里我们可以使用 Interface 来实现，上面的例子就可以改写为如下形式：</p>
                  <figure class="highlight typescript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">interface</span> LabeledValue &#123;</span><br><span class="line">  label: <span class="built_in">string</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">printLabel</span>(<span class="params">labeledObj: LabeledValue</span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(labeledObj.label);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> myObj = &#123; size: <span class="number">10</span>, label: <span class="string">"Size 10 Object"</span> &#125;;</span><br><span class="line">printLabel(myObj);</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里我们使用 interface 声明了一个类型声明，这样在 printLabel 就可以直接使用 Interface 的名称了。</p>
                  <p>怎么样？这种写法是不是感觉好多了。</p>
                  <h2 id="Optional-properties"><a href="#Optional-properties" class="headerlink" title="Optional properties"></a>Optional properties</h2>
                  <p>某些情况下，某些字段并不是完全必要的，比如看下面的例子：</p>
                  <figure class="highlight typescript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">interface</span> LabeledValue &#123;</span><br><span class="line">  label: <span class="built_in">string</span>;</span><br><span class="line">  count: <span class="built_in">number</span>,</span><br><span class="line">  message: <span class="built_in">string</span>,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">printLabel</span>(<span class="params">labeledObj: LabeledValue</span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(labeledObj.label);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> myObj = &#123; size: <span class="number">10</span>, count: <span class="number">1</span>, label: <span class="string">"Size 10 Object"</span>&#125;;</span><br><span class="line">printLabel(myObj);</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>其中 message 字段其实在 myObj 对象里面没有，而且这个字段也并不是必需的，但是该字段如果存在的话，必须是 string 类型。那像上面的写法，其实就会报错了：</p>
                  <figure class="highlight routeros">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">Argument of<span class="built_in"> type </span><span class="string">'&#123; size: number; count: number; label: string; &#125;'</span> is <span class="keyword">not</span> assignable <span class="keyword">to</span> parameter of<span class="built_in"> type </span><span class="string">'LabeledValue'</span>. Property <span class="string">'message'</span> is missing <span class="keyword">in</span><span class="built_in"> type </span><span class="string">'&#123; size: number; count: number; label: string; &#125;'</span> but required <span class="keyword">in</span><span class="built_in"> type </span><span class="string">'LabeledValue'</span>.</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里说 message 字段没有传。</p>
                  <p>这时候我们可以将 message 标识为可选字段，只需要在字段后面加个 <code>?</code> 就好了，写法如下：</p>
                  <figure class="highlight typescript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">interface</span> LabeledValue &#123;</span><br><span class="line">  label: <span class="built_in">string</span>;</span><br><span class="line">  count: <span class="built_in">number</span>,</span><br><span class="line">  message?: <span class="built_in">string</span>,</span><br><span class="line">&#125;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这样就不会再报错了。</p>
                  <h2 id="Readonly-properties"><a href="#Readonly-properties" class="headerlink" title="Readonly properties"></a>Readonly properties</h2>
                  <p>在某些情况下，我们期望一个 Object 的某些字段不能后续被修改，只能在创建的时候声明，这个怎么做到呢？很简单，将其设置为只读字段就好了，示例如下：</p>
                  <figure class="highlight typescript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">interface</span> Point &#123;</span><br><span class="line">  readonly x: <span class="built_in">number</span>;</span><br><span class="line">  readonly y: <span class="built_in">number</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> p1: Point = &#123; x: <span class="number">10</span>, y: <span class="number">20</span> &#125;;</span><br><span class="line">p1.x = <span class="number">5</span>; <span class="comment">// error!</span></span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里我们声明了一个名为 Point 的 Interface，然后在创建 Point 的时候将 x 设置为 10。但后续如果我们想设置 x 的属性为 5 的时候，就会报错了：</p>
                  <figure class="highlight applescript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">Cannot assign <span class="keyword">to</span> 'x' because <span class="keyword">it</span> <span class="keyword">is</span> a <span class="built_in">read</span>-only <span class="keyword">property</span>.</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这样就可以保证某些字段不能在后续操作流程中被修改，保证了安全性。</p>
                  <p>另外我们可以使用 ReadonlyArray 来声明不可变的 Array，一旦初始化完成之后，后续所有关于 Array 的操作都会报错，示例如下：</p>
                  <figure class="highlight typescript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">let</span> a: <span class="built_in">number</span>[] = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>];</span><br><span class="line"><span class="keyword">let</span> ro: ReadonlyArray&lt;<span class="built_in">number</span>&gt; = a;</span><br><span class="line"></span><br><span class="line">ro[<span class="number">0</span>] = <span class="number">12</span>; <span class="comment">// error!</span></span><br><span class="line">Index signature <span class="keyword">in</span> <span class="keyword">type</span> <span class="string">'readonly number[]'</span> only permits reading.</span><br><span class="line">ro.push(<span class="number">5</span>); <span class="comment">// error!</span></span><br><span class="line">Property <span class="string">'push'</span> does not exist on <span class="keyword">type</span> <span class="string">'readonly number[]'</span>.</span><br><span class="line">ro.length = <span class="number">100</span>; <span class="comment">// error!</span></span><br><span class="line">Cannot assign to <span class="string">'length'</span> because it is a read-only property.</span><br><span class="line">a = ro; <span class="comment">// error!</span></span><br><span class="line">The <span class="keyword">type</span> <span class="string">'readonly number[]'</span> is <span class="string">'readonly'</span> and cannot be assigned to the mutable <span class="keyword">type</span> <span class="string">'number[]'</span>.</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>另外到这里大家可能疑惑 readonly 和 const 是什么区别，二者不都代表不可修改吗？其实区分很简单，readonly 是用来修改 Object 的某个属性的，而 const 是用来修饰某个变量的。</p>
                  <h2 id="Function-Types"><a href="#Function-Types" class="headerlink" title="Function Types"></a>Function Types</h2>
                  <p>除了用 interface 声明 Object 的字段，我们还可以声明方法的一些规范，示例如下：</p>
                  <figure class="highlight typescript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">interface</span> SearchFunc &#123;</span><br><span class="line">  (source: <span class="built_in">string</span>, subString: <span class="built_in">string</span>): <span class="built_in">boolean</span>;</span><br><span class="line">&#125;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里就是用 interface 声明了一个 Function，前半部分是接收的参数类型，后面 boolean 是返回值类型。</p>
                  <p>声明 interface 之后，我们便可以声明一个 Function 了，写法如下：</p>
                  <figure class="highlight typescript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">interface</span> SearchFunc &#123;</span><br><span class="line">  (source: <span class="built_in">string</span>, subString: <span class="built_in">string</span>): <span class="built_in">boolean</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> mySearch: SearchFunc = <span class="function">(<span class="params">source: <span class="built_in">string</span>, subString: <span class="built_in">string</span></span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">let</span> result = source.search(subString);</span><br><span class="line">  <span class="keyword">return</span> result &gt; <span class="number">-1</span>;</span><br><span class="line">&#125;;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里声明了一个 Function 叫做 mySearch，其中其参数和返回值严格按照 SearchFunc 这个 Interface 来实现，那就没问题。</p>
                  <p>如果我们将返回值改掉，改成非 boolean 类型，示例如下：</p>
                  <figure class="highlight typescript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">interface</span> SearchFunc &#123;</span><br><span class="line">  (source: <span class="built_in">string</span>, subString: <span class="built_in">string</span>): <span class="built_in">boolean</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> mySearch: SearchFunc = <span class="function">(<span class="params">source: <span class="built_in">string</span>, subString: <span class="built_in">string</span></span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">let</span> result = source.search(subString);</span><br><span class="line">  <span class="keyword">return</span> result;</span><br><span class="line">&#125;;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这时候就会得到如下报错：</p>
                  <figure class="highlight routeros">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line">Type <span class="string">'(source: string, subString: string) =&gt; number'</span> is <span class="keyword">not</span> assignable <span class="keyword">to</span><span class="built_in"> type </span><span class="string">'SearchFunc'</span>.<span class="built_in"> Type </span><span class="string">'number'</span> is <span class="keyword">not</span> assignable <span class="keyword">to</span><span class="built_in"> type </span><span class="string">'boolean'</span>.</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里就说返回值是 number，而不是 boolean。</p>
                  <h2 id="Class-Types"><a href="#Class-Types" class="headerlink" title="Class Types"></a>Class Types</h2>
                  <p>除了声明 Function，interface 还可以用来声明 Class，主要作用就是声明 class 里面所必须的属性和方法，示例如下：</p>
                  <figure class="highlight typescript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">interface</span> ClockInterface &#123;</span><br><span class="line">  currentTime: <span class="built_in">Date</span>;</span><br><span class="line">  setTime(d: <span class="built_in">Date</span>): <span class="built_in">void</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Clock <span class="keyword">implements</span> ClockInterface &#123;</span><br><span class="line">  currentTime: <span class="built_in">Date</span> = <span class="keyword">new</span> <span class="built_in">Date</span>();</span><br><span class="line">  setTime(d: <span class="built_in">Date</span>) &#123;</span><br><span class="line">    <span class="keyword">this</span>.currentTime = d;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">constructor</span>(<span class="params">h: <span class="built_in">number</span>, m: <span class="built_in">number</span></span>) &#123;&#125;</span><br><span class="line">&#125;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这个简直跟其他语言的接口定义太像了。定义好了 ClockInterface 之后，class 需要使用 implements 来实现这个接口，同时必须要声明 currentTime 这个变量和 setTime 方法，类型也需要完全一致，不然就会报错。</p>
                  <h2 id="Extending-Interfaces"><a href="#Extending-Interfaces" class="headerlink" title="Extending Interfaces"></a>Extending Interfaces</h2>
                  <p>另外 Interface 之间也是可以继承的，相当于在一个 Interface 上进行扩展，示例如下：</p>
                  <figure class="highlight typescript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">interface</span> Shape &#123;</span><br><span class="line">  color: <span class="built_in">string</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> Square <span class="keyword">extends</span> Shape &#123;</span><br><span class="line">  sideLength: <span class="built_in">number</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> square = &#123;&#125; <span class="keyword">as</span> Square;</span><br><span class="line">square.color = <span class="string">"blue"</span>;</span><br><span class="line">square.sideLength = <span class="number">10</span>;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里 Shape 这个 Interface 只有 color 这个属性，而 Square 则继承了 Shape，并且加了 sideLength 属性，那其实现在 Square 这个接口声明了 color 和 sideLength 这两个属性。</p>
                  <p>另外 Interface 还支持多继承，获取被继承的 Interface 的所有声明，示例如下：</p>
                  <figure class="highlight typescript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">interface</span> Shape &#123;</span><br><span class="line">  color: <span class="built_in">string</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> PenStroke &#123;</span><br><span class="line">  penWidth: <span class="built_in">number</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> Square <span class="keyword">extends</span> Shape, PenStroke &#123;</span><br><span class="line">  sideLength: <span class="built_in">number</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> square = &#123;&#125; <span class="keyword">as</span> Square;</span><br><span class="line">square.color = <span class="string">"blue"</span>;</span><br><span class="line">square.sideLength = <span class="number">10</span>;</span><br><span class="line">square.penWidth = <span class="number">5.0</span>;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>但如果同名的字段不一致怎么办呢？比如下面的例子：</p>
                  <figure class="highlight typescript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">interface</span> Fruit &#123;</span><br><span class="line">    color: <span class="built_in">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> Apple <span class="keyword">extends</span> Fruit &#123;</span><br><span class="line">    hasLeaf: <span class="built_in">boolean</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> Orange <span class="keyword">extends</span> Fruit &#123;</span><br><span class="line">    size: <span class="built_in">number</span>,</span><br><span class="line">    hasLeaf: <span class="built_in">number</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> Watermalon <span class="keyword">extends</span> Apple, Orange &#123;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>这里 hasLeaf 在 Apple 里面是 boolean 类型，在 Orange 里面是 number 类型，最后 Watermalon 继承了这两个 Interface 会怎样呢？</p>
                  <p>很明显，报错了，结果如下：</p>
                  <figure class="highlight delphi">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">Interface</span> <span class="string">'Watermalon'</span> cannot simultaneously extend types <span class="string">'Apple'</span> <span class="keyword">and</span> <span class="string">'Orange'</span>. Named <span class="keyword">property</span> <span class="string">'hasLeaf'</span> <span class="keyword">of</span> types <span class="string">'Apple'</span> <span class="keyword">and</span> <span class="string">'Orange'</span> are <span class="keyword">not</span> identical.</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>意思就是说字段类型不一致。</p>
                  <p>所以，要多继承的话，需要被继承的 Interface 里面的属性不互相冲突，不然是无法同时继承的。</p>
                  <h2 id="Interfaces-Extending-Classes"><a href="#Interfaces-Extending-Classes" class="headerlink" title="Interfaces Extending Classes"></a>Interfaces Extending Classes</h2>
                  <p>在某些情况下，Interface 可能需要继承 Class，Interface 扩展 Class 时，它将继承该 Class 的成员，但不继承其实现。这就类似该 Interface 声明了该类的所有成员而没有提供实现。</p>
                  <p>另外 Interface 甚至可以继承 Class 的私有成员和受保护成员。这意味着，当创建一个扩展带有私有或受保护成员的 Class 的 Interface 时，该 Interface 只能由该 Class 或其子 Class 实现。</p>
                  <p>示例如下：</p>
                  <figure class="highlight typescript">
                    <table>
                      <tr>
                        <td class="gutter">
                          <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre>
                        </td>
                        <td class="code">
                          <pre><span class="line"><span class="keyword">class</span> Control &#123;</span><br><span class="line">  <span class="keyword">private</span> state: <span class="built_in">any</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> SelectableControl <span class="keyword">extends</span> Control &#123;</span><br><span class="line">  select(): <span class="built_in">void</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Button <span class="keyword">extends</span> Control <span class="keyword">implements</span> SelectableControl &#123;</span><br><span class="line">  select() &#123;&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> TextBox <span class="keyword">extends</span> Control &#123;</span><br><span class="line">  select() &#123;&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> ImageControl <span class="keyword">implements</span> SelectableControl &#123;</span><br><span class="line">  <span class="comment">// Error, Class 'ImageControl' incorrectly implements interface 'SelectableControl'.</span></span><br><span class="line">  <span class="comment">// Types have separate declarations of a private property 'state'.</span></span><br><span class="line">  <span class="keyword">private</span> state: <span class="built_in">any</span>;</span><br><span class="line">  select() &#123;&#125;</span><br><span class="line">&#125;</span><br></pre>
                        </td>
                      </tr>
                    </table>
                  </figure>
                  <p>上面我们可以知道，当创建一个扩展带有私有或受保护成员的 Class 的 Interface 时，该 Interface 只能由该 Class 或其子 Class 实现。在这里 ImageControl 由于没有继承 Control，但同时 Control 还包含了私有成员变量，所以 ImageControl 并不能继承得到 state 这个私有成员变量，所以会报错。</p>
                  <p>以上便是关于 Interface 的一些用法，后面会继续总结其他的用法，如 Functions、Classes 等详细用法。</p>
                  </p>
                </div>
              </div>
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-user"></i>
                  </span>
                  <span class="post-meta-item-text">作者</span>
                  <span><a href="/authors/崔庆才" class="author" itemprop="url" rel="index">崔庆才</a></span>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>
                  <time title="创建时间：2020-12-30 02:16:52" itemprop="dateCreated datePublished" datetime="2020-12-30T02:16:52+08:00">2020-12-30</time>
                </span>
                <span id="/30001.html" class="post-meta-item leancloud_visitors" data-flag-title="TypeScript教程二之接口" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="fa fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
                <span class="post-meta-item" title="本文字数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-file-word"></i>
                  </span>
                  <span class="post-meta-item-text">本文字数：</span>
                  <span>6.6k</span>
                </span>
                <span class="post-meta-item" title="阅读时长">
                  <span class="post-meta-item-icon">
                    <i class="far fa-clock"></i>
                  </span>
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                  <span>6 分钟</span>
                </span>
              </div>
            </article>
            <script>
              document.querySelectorAll('.random').forEach(item => item.src = "https://picsum.photos/id/" + Math.floor(Math.random() * Math.floor(300)) + "/200/133")

            </script>
            <nav class="pagination">
              <a class="extend prev" rel="prev" href="/page/4/"><i class="fa fa-angle-left" aria-label="上一页"></i></a><a class="page-number" href="/">1</a><span class="space">&hellip;</span><a class="page-number" href="/page/4/">4</a><span class="page-number current">5</span><a class="page-number" href="/page/6/">6</a><span class="space">&hellip;</span><a class="page-number" href="/page/31/">31</a><a class="extend next" rel="next" href="/page/6/"><i class="fa fa-angle-right" aria-label="下一页"></i></a>
            </nav>
          </div>
          <script>
            window.addEventListener('tabs:register', () =>
            {
              let
              {
                activeClass
              } = CONFIG.comments;
              if (CONFIG.comments.storage)
              {
                activeClass = localStorage.getItem('comments_active') || activeClass;
              }
              if (activeClass)
              {
                let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
                if (activeTab)
                {
                  activeTab.click();
                }
              }
            });
            if (CONFIG.comments.storage)
            {
              window.addEventListener('tabs:click', event =>
              {
                if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
                let commentClass = event.target.classList[1];
                localStorage.setItem('comments_active', commentClass);
              });
            }

          </script>
        </div>
        <div class="toggle sidebar-toggle">
          <span class="toggle-line toggle-line-first"></span>
          <span class="toggle-line toggle-line-middle"></span>
          <span class="toggle-line toggle-line-last"></span>
        </div>
        <aside class="sidebar">
          <div class="sidebar-inner">
            <ul class="sidebar-nav motion-element">
              <li class="sidebar-nav-toc"> 文章目录 </li>
              <li class="sidebar-nav-overview"> 站点概览 </li>
            </ul>
            <!--noindex-->
            <div class="post-toc-wrap sidebar-panel">
            </div>
            <!--/noindex-->
            <div class="site-overview-wrap sidebar-panel">
              <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
                <img class="site-author-image" itemprop="image" alt="崔庆才" src="/images/avatar.png">
                <p class="site-author-name" itemprop="name">崔庆才</p>
                <div class="site-description" itemprop="description">崔庆才的个人站点，记录生活的瞬间，分享学习的心得。</div>
              </div>
              <div class="site-state-wrap motion-element">
                <nav class="site-state">
                  <div class="site-state-item site-state-posts">
                    <a href="/archives/">
                      <span class="site-state-item-count">608</span>
                      <span class="site-state-item-name">日志</span>
                    </a>
                  </div>
                  <div class="site-state-item site-state-categories">
                    <a href="/categories/">
                      <span class="site-state-item-count">24</span>
                      <span class="site-state-item-name">分类</span></a>
                  </div>
                  <div class="site-state-item site-state-tags">
                    <a href="/tags/">
                      <span class="site-state-item-count">156</span>
                      <span class="site-state-item-name">标签</span></a>
                  </div>
                </nav>
              </div>
              <div class="links-of-author motion-element">
                <span class="links-of-author-item">
                  <a href="https://github.com/Germey" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;Germey" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
                </span>
                <span class="links-of-author-item">
                  <a href="mailto:cqc@cuiqingcai.com.com" title="邮件 → mailto:cqc@cuiqingcai.com.com" rel="noopener" target="_blank"><i class="fa fa-envelope fa-fw"></i>邮件</a>
                </span>
                <span class="links-of-author-item">
                  <a href="https://weibo.com/cuiqingcai" title="微博 → https:&#x2F;&#x2F;weibo.com&#x2F;cuiqingcai" rel="noopener" target="_blank"><i class="fab fa-weibo fa-fw"></i>微博</a>
                </span>
                <span class="links-of-author-item">
                  <a href="https://www.zhihu.com/people/Germey" title="知乎 → https:&#x2F;&#x2F;www.zhihu.com&#x2F;people&#x2F;Germey" rel="noopener" target="_blank"><i class="fa fa-magic fa-fw"></i>知乎</a>
                </span>
              </div>
            </div>
            <div style=" width: 100%;" class="sidebar-panel sidebar-panel-image sidebar-panel-active">
              <a href="https://tutorial.lengyue.video/?coupon=12ef4b1a-a3db-11ea-bb37-0242ac130002_cqx_850" target="_blank" rel="noopener">
                <img src="https://qiniu.cuiqingcai.com/bco2a.png" style=" width: 100%;">
              </a>
            </div>
            <div style=" width: 100%;" class="sidebar-panel sidebar-panel-image sidebar-panel-active">
              <a href="http://www.ipidea.net/?utm-source=cqc&utm-keyword=?cqc" target="_blank" rel="noopener">
                <img src="https://qiniu.cuiqingcai.com/0ywun.png" style=" width: 100%;">
              </a>
            </div>
            <div class="sidebar-panel sidebar-panel-tags sidebar-panel-active">
              <h4 class="name"> 标签云 </h4>
              <div class="content">
                <a href="/tags/2048/" style="font-size: 10px;">2048</a> <a href="/tags/API/" style="font-size: 10px;">API</a> <a href="/tags/Bootstrap/" style="font-size: 11.25px;">Bootstrap</a> <a href="/tags/CDN/" style="font-size: 10px;">CDN</a> <a href="/tags/CQC/" style="font-size: 10px;">CQC</a> <a href="/tags/CSS/" style="font-size: 10px;">CSS</a> <a href="/tags/CSS-%E5%8F%8D%E7%88%AC%E8%99%AB/" style="font-size: 10px;">CSS 反爬虫</a> <a href="/tags/CV/" style="font-size: 10px;">CV</a> <a href="/tags/Django/" style="font-size: 10px;">Django</a> <a href="/tags/Eclipse/" style="font-size: 11.25px;">Eclipse</a> <a href="/tags/FTP/" style="font-size: 10px;">FTP</a> <a href="/tags/Git/" style="font-size: 10px;">Git</a> <a href="/tags/GitHub/" style="font-size: 13.75px;">GitHub</a> <a href="/tags/HTML5/" style="font-size: 10px;">HTML5</a> <a href="/tags/Hexo/" style="font-size: 10px;">Hexo</a> <a href="/tags/IT/" style="font-size: 10px;">IT</a> <a href="/tags/JSP/" style="font-size: 10px;">JSP</a> <a href="/tags/JavaScript/" style="font-size: 10px;">JavaScript</a> <a href="/tags/K8s/" style="font-size: 10px;">K8s</a> <a href="/tags/LOGO/" style="font-size: 10px;">LOGO</a> <a href="/tags/Linux/" style="font-size: 10px;">Linux</a> <a href="/tags/MIUI/" style="font-size: 10px;">MIUI</a> <a href="/tags/MongoDB/" style="font-size: 10px;">MongoDB</a> <a href="/tags/Mysql/" style="font-size: 10px;">Mysql</a> <a href="/tags/NBA/" style="font-size: 10px;">NBA</a> <a href="/tags/PHP/" style="font-size: 11.25px;">PHP</a> <a href="/tags/PS/" style="font-size: 10px;">PS</a> <a href="/tags/Pathlib/" style="font-size: 10px;">Pathlib</a> <a href="/tags/PhantomJS/" style="font-size: 10px;">PhantomJS</a> <a href="/tags/Python/" style="font-size: 15px;">Python</a> <a href="/tags/Python3/" style="font-size: 12.5px;">Python3</a> <a href="/tags/Pythonic/" style="font-size: 10px;">Pythonic</a> <a href="/tags/QQ/" style="font-size: 10px;">QQ</a> <a href="/tags/Redis/" style="font-size: 10px;">Redis</a> <a href="/tags/SAE/" style="font-size: 10px;">SAE</a> <a href="/tags/SSH/" style="font-size: 10px;">SSH</a> <a href="/tags/SVG/" style="font-size: 10px;">SVG</a> <a href="/tags/Scrapy/" style="font-size: 10px;">Scrapy</a> <a href="/tags/Scrapy-redis/" style="font-size: 10px;">Scrapy-redis</a> <a href="/tags/Scrapy%E5%88%86%E5%B8%83%E5%BC%8F/" style="font-size: 10px;">Scrapy分布式</a> <a href="/tags/Selenium/" style="font-size: 10px;">Selenium</a> <a href="/tags/TKE/" style="font-size: 10px;">TKE</a> <a href="/tags/Ubuntu/" style="font-size: 11.25px;">Ubuntu</a> <a href="/tags/VS-Code/" style="font-size: 10px;">VS Code</a> <a href="/tags/Vs-Code/" style="font-size: 10px;">Vs Code</a> <a href="/tags/Vue/" style="font-size: 11.25px;">Vue</a> <a href="/tags/Webpack/" style="font-size: 10px;">Webpack</a> <a href="/tags/Windows/" style="font-size: 10px;">Windows</a> <a href="/tags/Winpcap/" style="font-size: 10px;">Winpcap</a> <a href="/tags/WordPress/" style="font-size: 13.75px;">WordPress</a> <a href="/tags/Youtube/" style="font-size: 11.25px;">Youtube</a> <a href="/tags/android/" style="font-size: 10px;">android</a> <a href="/tags/ansible/" style="font-size: 10px;">ansible</a> <a href="/tags/cocos2d-x/" style="font-size: 10px;">cocos2d-x</a> <a href="/tags/e6/" style="font-size: 10px;">e6</a> <a href="/tags/fitvids/" style="font-size: 10px;">fitvids</a> <a href="/tags/git/" style="font-size: 11.25px;">git</a> <a href="/tags/json/" style="font-size: 10px;">json</a> <a href="/tags/js%E9%80%86%E5%90%91/" style="font-size: 10px;">js逆向</a> <a href="/tags/kubernetes/" style="font-size: 10px;">kubernetes</a> <a href="/tags/log/" style="font-size: 10px;">log</a> <a href="/tags/logging/" style="font-size: 10px;">logging</a> <a href="/tags/matlab/" style="font-size: 11.25px;">matlab</a> <a href="/tags/python/" style="font-size: 20px;">python</a> <a href="/tags/pytube/" style="font-size: 11.25px;">pytube</a> <a href="/tags/pywin32/" style="font-size: 10px;">pywin32</a> <a href="/tags/style/" style="font-size: 10px;">style</a> <a href="/tags/tomcat/" style="font-size: 10px;">tomcat</a> <a href="/tags/ubuntu/" style="font-size: 10px;">ubuntu</a> <a href="/tags/uwsgi/" style="font-size: 10px;">uwsgi</a> <a href="/tags/vsftpd/" style="font-size: 10px;">vsftpd</a> <a href="/tags/wamp/" style="font-size: 10px;">wamp</a> <a href="/tags/wineQQ/" style="font-size: 10px;">wineQQ</a> <a href="/tags/%E4%B8%83%E7%89%9B/" style="font-size: 11.25px;">七牛</a> <a href="/tags/%E4%B8%8A%E6%B5%B7/" style="font-size: 10px;">上海</a> <a href="/tags/%E4%B8%AA%E4%BA%BA%E7%BD%91%E7%AB%99/" style="font-size: 10px;">个人网站</a> <a href="/tags/%E4%B8%BB%E9%A2%98/" style="font-size: 10px;">主题</a> <a href="/tags/%E4%BA%91%E4%BA%A7%E5%93%81/" style="font-size: 10px;">云产品</a> <a href="/tags/%E4%BA%91%E5%AD%98%E5%82%A8/" style="font-size: 10px;">云存储</a> <a href="/tags/%E4%BA%AC%E4%B8%9C%E4%BA%91/" style="font-size: 10px;">京东云</a> <a href="/tags/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/" style="font-size: 12.5px;">人工智能</a> <a href="/tags/%E4%BB%A3%E7%90%86/" style="font-size: 10px;">代理</a> <a href="/tags/%E4%BB%A3%E7%A0%81/" style="font-size: 10px;">代码</a> <a href="/tags/%E4%BB%A3%E7%A0%81%E5%88%86%E4%BA%AB%E5%9B%BE/" style="font-size: 10px;">代码分享图</a> <a href="/tags/%E4%BC%98%E5%8C%96/" style="font-size: 10px;">优化</a> <a href="/tags/%E4%BD%8D%E8%BF%90%E7%AE%97/" style="font-size: 10px;">位运算</a> <a href="/tags/%E5%85%AC%E4%BC%97%E5%8F%B7/" style="font-size: 10px;">公众号</a> <a href="/tags/%E5%88%86%E4%BA%AB/" style="font-size: 10px;">分享</a> <a href="/tags/%E5%88%86%E5%B8%83%E5%BC%8F/" style="font-size: 10px;">分布式</a> <a href="/tags/%E5%88%9B%E4%B8%9A/" style="font-size: 10px;">创业</a> <a href="/tags/%E5%89%8D%E7%AB%AF/" style="font-size: 12.5px;">前端</a> <a href="/tags/%E5%8D%9A%E5%AE%A2/" style="font-size: 10px;">博客</a> <a href="/tags/%E5%8E%9F%E7%94%9FAPP/" style="font-size: 10px;">原生APP</a> <a href="/tags/%E5%8F%8D%E7%88%AC%E8%99%AB/" style="font-size: 12.5px;">反爬虫</a> <a href="/tags/%E5%91%BD%E4%BB%A4/" style="font-size: 10px;">命令</a> <a href="/tags/%E5%93%8D%E5%BA%94%E5%BC%8F%E5%B8%83%E5%B1%80/" style="font-size: 10px;">响应式布局</a> <a href="/tags/%E5%9E%83%E5%9C%BE%E9%82%AE%E4%BB%B6/" style="font-size: 10px;">垃圾邮件</a> <a href="/tags/%E5%9F%9F%E5%90%8D%E7%BB%91%E5%AE%9A/" style="font-size: 10px;">域名绑定</a> <a href="/tags/%E5%A4%8D%E7%9B%98/" style="font-size: 10px;">复盘</a> <a href="/tags/%E5%A4%A7%E4%BC%97%E7%82%B9%E8%AF%84/" style="font-size: 10px;">大众点评</a> <a href="/tags/%E5%AD%97%E4%BD%93%E5%8F%8D%E7%88%AC%E8%99%AB/" style="font-size: 10px;">字体反爬虫</a> <a href="/tags/%E5%AD%97%E7%AC%A6%E9%97%AE%E9%A2%98/" style="font-size: 10px;">字符问题</a> <a href="/tags/%E5%AD%A6%E4%B9%A0%E6%96%B9%E6%B3%95/" style="font-size: 10px;">学习方法</a> <a href="/tags/%E5%AE%89%E5%8D%93/" style="font-size: 10px;">安卓</a> <a href="/tags/%E5%AE%9E%E7%94%A8/" style="font-size: 10px;">实用</a> <a href="/tags/%E5%B0%81%E9%9D%A2/" style="font-size: 10px;">封面</a> <a href="/tags/%E5%B4%94%E5%BA%86%E6%89%8D/" style="font-size: 18.75px;">崔庆才</a> <a href="/tags/%E5%B7%A5%E5%85%B7/" style="font-size: 12.5px;">工具</a> <a href="/tags/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/" style="font-size: 10px;">开发工具</a> <a href="/tags/%E5%BE%AE%E8%BD%AF/" style="font-size: 10px;">微软</a> <a href="/tags/%E6%80%9D%E8%80%83/" style="font-size: 10px;">思考</a> <a href="/tags/%E6%89%8B%E6%9C%BA%E8%AE%BF%E9%97%AE/" style="font-size: 10px;">手机访问</a> <a href="/tags/%E6%95%99%E7%A8%8B/" style="font-size: 10px;">教程</a> <a href="/tags/%E6%95%99%E8%82%B2/" style="font-size: 10px;">教育</a> <a href="/tags/%E6%96%B0%E4%B9%A6/" style="font-size: 12.5px;">新书</a> <a href="/tags/%E6%96%B9%E6%B3%95%E8%AE%BA/" style="font-size: 10px;">方法论</a> <a href="/tags/%E6%97%85%E6%B8%B8/" style="font-size: 10px;">旅游</a> <a href="/tags/%E6%97%A5%E5%BF%97/" style="font-size: 10px;">日志</a> <a href="/tags/%E6%9A%97%E6%97%B6%E9%97%B4/" style="font-size: 10px;">暗时间</a> <a href="/tags/%E6%9D%9C%E5%85%B0%E7%89%B9/" style="font-size: 11.25px;">杜兰特</a> <a href="/tags/%E6%A1%8C%E9%9D%A2/" style="font-size: 10px;">桌面</a> <a href="/tags/%E6%AD%8C%E5%8D%95/" style="font-size: 10px;">歌单</a> <a href="/tags/%E6%B1%9F%E5%8D%97/" style="font-size: 10px;">江南</a> <a href="/tags/%E6%B8%B8%E6%88%8F/" style="font-size: 10px;">游戏</a> <a href="/tags/%E7%84%A6%E8%99%91/" style="font-size: 10px;">焦虑</a> <a href="/tags/%E7%88%AC%E8%99%AB/" style="font-size: 16.25px;">爬虫</a> <a href="/tags/%E7%88%AC%E8%99%AB%E4%B9%A6%E7%B1%8D/" style="font-size: 11.25px;">爬虫书籍</a> <a href="/tags/%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F/" style="font-size: 10px;">环境变量</a> <a href="/tags/%E7%94%9F%E6%B4%BB%E7%AC%94%E8%AE%B0/" style="font-size: 10px;">生活笔记</a> <a href="/tags/%E7%99%BB%E5%BD%95/" style="font-size: 10px;">登录</a> <a href="/tags/%E7%9F%A5%E4%B9%8E/" style="font-size: 10px;">知乎</a> <a href="/tags/%E7%9F%AD%E4%BF%A1/" style="font-size: 10px;">短信</a> <a href="/tags/%E7%9F%AD%E4%BF%A1%E9%AA%8C%E8%AF%81%E7%A0%81/" style="font-size: 10px;">短信验证码</a> <a href="/tags/%E7%AC%94%E8%AE%B0%E8%BD%AF%E4%BB%B6/" style="font-size: 10px;">笔记软件</a> <a href="/tags/%E7%AF%AE%E7%BD%91/" style="font-size: 10px;">篮网</a> <a href="/tags/%E7%BA%B8%E5%BC%A0/" style="font-size: 10px;">纸张</a> <a href="/tags/%E7%BB%84%E4%BB%B6/" style="font-size: 10px;">组件</a> <a href="/tags/%E7%BD%91%E7%AB%99/" style="font-size: 10px;">网站</a> <a href="/tags/%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB/" style="font-size: 11.25px;">网络爬虫</a> <a href="/tags/%E7%BE%8E%E5%AD%A6/" style="font-size: 10px;">美学</a> <a href="/tags/%E8%82%89%E5%A4%B9%E9%A6%8D/" style="font-size: 10px;">肉夹馍</a> <a href="/tags/%E8%85%BE%E8%AE%AF%E4%BA%91/" style="font-size: 10px;">腾讯云</a> <a href="/tags/%E8%87%AA%E5%BE%8B/" style="font-size: 10px;">自律</a> <a href="/tags/%E8%A5%BF%E5%B0%91%E7%88%B7/" style="font-size: 10px;">西少爷</a> <a href="/tags/%E8%A7%86%E9%A2%91/" style="font-size: 10px;">视频</a> <a href="/tags/%E8%B0%B7%E6%AD%8C%E9%AA%8C%E8%AF%81%E7%A0%81/" style="font-size: 10px;">谷歌验证码</a> <a href="/tags/%E8%BF%90%E8%90%A5/" style="font-size: 10px;">运营</a> <a href="/tags/%E8%BF%9C%E7%A8%8B/" style="font-size: 10px;">远程</a> <a href="/tags/%E9%80%86%E5%90%91/" style="font-size: 10px;">逆向</a> <a href="/tags/%E9%85%8D%E7%BD%AE/" style="font-size: 10px;">配置</a> <a href="/tags/%E9%87%8D%E8%A3%85/" style="font-size: 10px;">重装</a> <a href="/tags/%E9%98%BF%E6%9D%9C/" style="font-size: 10px;">阿杜</a> <a href="/tags/%E9%9D%99%E8%A7%85/" style="font-size: 17.5px;">静觅</a> <a href="/tags/%E9%A2%A0%E8%A6%86/" style="font-size: 10px;">颠覆</a> <a href="/tags/%E9%A3%9E%E4%BF%A1/" style="font-size: 10px;">飞信</a> <a href="/tags/%E9%B8%BF%E8%92%99/" style="font-size: 10px;">鸿蒙</a>
              </div>
              <script>
                const tagsColors = ['#00a67c', '#5cb85c', '#d9534f', '#567e95', '#b37333', '#f4843d', '#15a287']
                const tagsElements = document.querySelectorAll('.sidebar-panel-tags .content a')
                tagsElements.forEach((item) =>
                {
                  item.style.backgroundColor = tagsColors[Math.floor(Math.random() * tagsColors.length)]
                })

              </script>
            </div>
            <div class="sidebar-panel sidebar-panel-categories sidebar-panel-active">
              <h4 class="name"> 分类 </h4>
              <div class="content">
                <ul class="category-list">
                  <li class="category-list-item"><a class="category-list-link" href="/categories/C-C/">C/C++</a><span class="category-list-count">23</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/HTML/">HTML</a><span class="category-list-count">14</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/Java/">Java</a><span class="category-list-count">5</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/JavaScript/">JavaScript</a><span class="category-list-count">26</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/Linux/">Linux</a><span class="category-list-count">15</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/Markdown/">Markdown</a><span class="category-list-count">1</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/Net/">Net</a><span class="category-list-count">4</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/Other/">Other</a><span class="category-list-count">39</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/PHP/">PHP</a><span class="category-list-count">27</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/Paper/">Paper</a><span class="category-list-count">2</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/Python/">Python</a><span class="category-list-count">261</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/TypeScript/">TypeScript</a><span class="category-list-count">2</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/%E4%B8%AA%E4%BA%BA%E5%B1%95%E7%A4%BA/">个人展示</a><span class="category-list-count">1</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/%E4%B8%AA%E4%BA%BA%E6%97%A5%E8%AE%B0/">个人日记</a><span class="category-list-count">9</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/%E4%B8%AA%E4%BA%BA%E8%AE%B0%E5%BD%95/">个人记录</a><span class="category-list-count">4</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E7%AC%94/">个人随笔</a><span class="category-list-count">15</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/%E5%AE%89%E8%A3%85%E9%85%8D%E7%BD%AE/">安装配置</a><span class="category-list-count">59</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/%E6%8A%80%E6%9C%AF%E6%9D%82%E8%B0%88/">技术杂谈</a><span class="category-list-count">88</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/%E6%9C%AA%E5%88%86%E7%B1%BB/">未分类</a><span class="category-list-count">1</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/%E7%94%9F%E6%B4%BB%E7%AC%94%E8%AE%B0/">生活笔记</a><span class="category-list-count">1</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/%E7%A6%8F%E5%88%A9%E4%B8%93%E5%8C%BA/">福利专区</a><span class="category-list-count">6</span></li>
                  <li class="category-list-item"><a class="category-list-link" href="/categories/%E8%81%8C%E4%BD%8D%E6%8E%A8%E8%8D%90/">职位推荐</a><span class="category-list-count">2</span></li>
                </ul>
              </div>
            </div>
            <div class="sidebar-panel sidebar-panel-friends sidebar-panel-active">
              <h4 class="name"> 友情链接 </h4>
              <ul class="friends">
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/j2dub.jpg">
                  </span>
                  <span class="link">
                    <a href="https://www.findhao.net/" target="_blank" rel="noopener">FindHao</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/ou6mm.jpg">
                  </span>
                  <span class="link">
                    <a href="https://diygod.me/" target="_blank" rel="noopener">DIYgod</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/6apxu.jpg">
                  </span>
                  <span class="link">
                    <a href="https://www.51dev.com/" target="_blank" rel="noopener">IT技术社区</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://www.jankl.com/img/titleshu.jpg">
                  </span>
                  <span class="link">
                    <a href="https://www.jankl.com/" target="_blank" rel="noopener">liberalist</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/bqlbs.png">
                  </span>
                  <span class="link">
                    <a href="http://www.urselect.com/" target="_blank" rel="noopener">优社电商</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/8s88c.jpg">
                  </span>
                  <span class="link">
                    <a href="https://www.yuanrenxue.com/" target="_blank" rel="noopener">猿人学</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/2wgg5.jpg">
                  </span>
                  <span class="link">
                    <a href="https://www.yunlifang.cn/" target="_blank" rel="noopener">云立方</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/shwr6.png">
                  </span>
                  <span class="link">
                    <a href="http://lanbing510.info/" target="_blank" rel="noopener">冰蓝</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/blvoh.jpg">
                  </span>
                  <span class="link">
                    <a href="https://lengyue.me/" target="_blank" rel="noopener">冷月</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="http://qianxunclub.com/favicon.png">
                  </span>
                  <span class="link">
                    <a href="http://qianxunclub.com/" target="_blank" rel="noopener">千寻啊千寻</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/0044u.jpg">
                  </span>
                  <span class="link">
                    <a href="http://kodcloud.com/" target="_blank" rel="noopener">可道云</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/ygnpn.jpg">
                  </span>
                  <span class="link">
                    <a href="http://www.kunkundashen.cn/" target="_blank" rel="noopener">坤坤大神</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/22uv1.png">
                  </span>
                  <span class="link">
                    <a href="http://www.cenchong.com/" target="_blank" rel="noopener">岑冲博客</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/ev9kl.png">
                  </span>
                  <span class="link">
                    <a href="http://www.zxiaoji.com/" target="_blank" rel="noopener">张小鸡</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://www.503error.com/favicon.ico">
                  </span>
                  <span class="link">
                    <a href="https://www.503error.com/" target="_blank" rel="noopener">张志明个人博客</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/x714o.jpg">
                  </span>
                  <span class="link">
                    <a href="http://www.hubwiz.com/" target="_blank" rel="noopener">汇智网</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/129d8.png">
                  </span>
                  <span class="link">
                    <a href="https://www.bysocket.com/" target="_blank" rel="noopener">泥瓦匠BYSocket</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://www.xiongge.club/favicon.ico">
                  </span>
                  <span class="link">
                    <a href="https://www.xiongge.club/" target="_blank" rel="noopener">熊哥club</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/3w4fe.png">
                  </span>
                  <span class="link">
                    <a href="https://zerlong.com/" target="_blank" rel="noopener">知语</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/44hxf.png">
                  </span>
                  <span class="link">
                    <a href="http://redstonewill.com/" target="_blank" rel="noopener">红色石头</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/8g1fk.jpg">
                  </span>
                  <span class="link">
                    <a href="http://www.laodong.me/" target="_blank" rel="noopener">老董博客</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/wkaus.jpg">
                  </span>
                  <span class="link">
                    <a href="https://zhaoshuai.me/" target="_blank" rel="noopener">碎念</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/pgo0r.jpg">
                  </span>
                  <span class="link">
                    <a href="https://www.chenwenguan.com/" target="_blank" rel="noopener">陈文管的博客</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/kk82a.jpg">
                  </span>
                  <span class="link">
                    <a href="https://www.lxlinux.net/" target="_blank" rel="noopener">良许Linux教程网</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/lj0t2.jpg">
                  </span>
                  <span class="link">
                    <a href="https://tanqingbo.cn/" target="_blank" rel="noopener">IT码农</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/i8cdr.png">
                  </span>
                  <span class="link">
                    <a href="https://junyiseo.com/" target="_blank" rel="noopener">均益个人博客</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/chwv2.png">
                  </span>
                  <span class="link">
                    <a href="https://brucedone.com/" target="_blank" rel="noopener">大鱼的鱼塘</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/2y43o.png">
                  </span>
                  <span class="link">
                    <a href="http://bbs.nightteam.cn/" target="_blank" rel="noopener">夜幕爬虫安全论坛</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/zvc3w.jpg">
                  </span>
                  <span class="link">
                    <a href="https://www.weishidong.com/" target="_blank" rel="noopener">韦世东的技术专栏</a>
                  </span>
                </li>
                <li class="friend">
                  <span class="logo">
                    <img src="https://qiniu.cuiqingcai.com/ebudy.jpg">
                  </span>
                  <span class="link">
                    <a href="https://chuanjiabing.com/" target="_blank" rel="noopener">穿甲兵技术社区</a>
                  </span>
                </li>
              </ul>
            </div>
          </div>
        </aside>
        <div id="sidebar-dimmer"></div>
      </div>
    </main>
    <footer class="footer">
      <div class="footer-inner">
        <div class="copyright"> &copy; <span itemprop="copyrightYear">2021</span>
          <span class="with-love">
            <i class="fa fa-heart"></i>
          </span>
          <span class="author" itemprop="copyrightHolder">崔庆才丨静觅</span>
          <span class="post-meta-divider">|</span>
          <span class="post-meta-item-icon">
            <i class="fa fa-chart-area"></i>
          </span>
          <span title="站点总字数">2.6m</span>
          <span class="post-meta-divider">|</span>
          <span class="post-meta-item-icon">
            <i class="fa fa-coffee"></i>
          </span>
          <span title="站点阅读时长">39:54</span>
        </div>
        <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://pisces.theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Pisces</a> 强力驱动 </div>
        <div class="beian"><a href="https://beian.miit.gov.cn/" rel="noopener" target="_blank">京ICP备18015597号-1 </a>
        </div>
        <script>
          (function ()
          {
            function leancloudSelector(url)
            {
              url = encodeURI(url);
              return document.getElementById(url).querySelector('.leancloud-visitors-count');
            }

            function addCount(Counter)
            {
              var visitors = document.querySelector('.leancloud_visitors');
              var url = decodeURI(visitors.id);
              var title = visitors.dataset.flagTitle;
              Counter('get', '/classes/Counter?where=' + encodeURIComponent(JSON.stringify(
              {
                url
              }))).then(response => response.json()).then((
              {
                results
              }) =>
              {
                if (results.length > 0)
                {
                  var counter = results[0];
                  leancloudSelector(url).innerText = counter.time + 1;
                  Counter('put', '/classes/Counter/' + counter.objectId,
                  {
                    time:
                    {
                      '__op': 'Increment',
                      'amount': 1
                    }
                  }).catch(error =>
                  {
                    console.error('Failed to save visitor count', error);
                  });
                }
                else
                {
                  Counter('post', '/classes/Counter',
                  {
                    title,
                    url,
                    time: 1
                  }).then(response => response.json()).then(() =>
                  {
                    leancloudSelector(url).innerText = 1;
                  }).catch(error =>
                  {
                    console.error('Failed to create', error);
                  });
                }
              }).catch(error =>
              {
                console.error('LeanCloud Counter Error', error);
              });
            }

            function showTime(Counter)
            {
              var visitors = document.querySelectorAll('.leancloud_visitors');
              var entries = [...visitors].map(element =>
              {
                return decodeURI(element.id);
              });
              Counter('get', '/classes/Counter?where=' + encodeURIComponent(JSON.stringify(
              {
                url:
                {
                  '$in': entries
                }
              }))).then(response => response.json()).then((
              {
                results
              }) =>
              {
                for (let url of entries)
                {
                  let target = results.find(item => item.url === url);
                  leancloudSelector(url).innerText = target ? target.time : 0;
                }
              }).catch(error =>
              {
                console.error('LeanCloud Counter Error', error);
              });
            }
            let
            {
              app_id,
              app_key,
              server_url
            } = {
              "enable": true,
              "app_id": "6X5dRQ0pnPWJgYy8SXOg0uID-gzGzoHsz",
              "app_key": "ziLDVEy73ne5HtFTiGstzHMS",
              "server_url": "https://6x5drq0p.lc-cn-n1-shared.com",
              "security": false
            };

            function fetchData(api_server)
            {
              var Counter = (method, url, data) =>
              {
                return fetch(`${api_server}/1.1${url}`,
                {
                  method,
                  headers:
                  {
                    'X-LC-Id': app_id,
                    'X-LC-Key': app_key,
                    'Content-Type': 'application/json',
                  },
                  body: JSON.stringify(data)
                });
              };
              if (CONFIG.page.isPost)
              {
                if (CONFIG.hostname !== location.hostname) return;
                addCount(Counter);
              }
              else if (document.querySelectorAll('.post-title-link').length >= 1)
              {
                showTime(Counter);
              }
            }
            let api_server = app_id.slice(-9) !== '-MdYXbMMI' ? server_url : `https://${app_id.slice(0, 8).toLowerCase()}.api.lncldglobal.com`;
            if (api_server)
            {
              fetchData(api_server);
            }
            else
            {
              fetch('https://app-router.leancloud.cn/2/route?appId=' + app_id).then(response => response.json()).then((
              {
                api_server
              }) =>
              {
                fetchData('https://' + api_server);
              });
            }
          })();

        </script>
      </div>
      <div class="footer-stat">
        <span id="cnzz_stat_icon_1279355174"></span>
        <script type="text/javascript">
          document.write(unescape("%3Cspan id='cnzz_stat_icon_1279355174'%3E%3C/span%3E%3Cscript src='https://v1.cnzz.com/z_stat.php%3Fid%3D1279355174%26online%3D1%26show%3Dline' type='text/javascript'%3E%3C/script%3E"));

        </script>
      </div>
    </footer>
  </div>
  <script src="//cdn.jsdelivr.net/npm/animejs@3.2.1/lib/anime.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/pangu@4/dist/browser/pangu.min.js"></script>
  <script src="/js/utils.js"></script>
  <script src="/.js"></script>
  <script src="/js/schemes/pisces.js"></script>
  <script src="/.js"></script>
  <script src="/js/next-boot.js"></script>
  <script src="/.js"></script>
  <script>
    (function ()
    {
      var canonicalURL, curProtocol;
      //Get the <link> tag
      var x = document.getElementsByTagName("link");
      //Find the last canonical URL
      if (x.length > 0)
      {
        for (i = 0; i < x.length; i++)
        {
          if (x[i].rel.toLowerCase() == 'canonical' && x[i].href)
          {
            canonicalURL = x[i].href;
          }
        }
      }
      //Get protocol
      if (!canonicalURL)
      {
        curProtocol = window.location.protocol.split(':')[0];
      }
      else
      {
        curProtocol = canonicalURL.split(':')[0];
      }
      //Get current URL if the canonical URL does not exist
      if (!canonicalURL) canonicalURL = window.location.href;
      //Assign script content. Replace current URL with the canonical URL
      ! function ()
      {
        var e = /([http|https]:\/\/[a-zA-Z0-9\_\.]+\.baidu\.com)/gi,
          r = canonicalURL,
          t = document.referrer;
        if (!e.test(r))
        {
          var n = (String(curProtocol).toLowerCase() === 'https') ? "https://sp0.baidu.com/9_Q4simg2RQJ8t7jm9iCKT-xh_/s.gif" : "//api.share.baidu.com/s.gif";
          t ? (n += "?r=" + encodeURIComponent(document.referrer), r && (n += "&l=" + r)) : r && (n += "?l=" + r);
          var i = new Image;
          i.src = n
        }
      }(window);
    })();

  </script>
  <script src="/js/local-search.js"></script>
  <script src="/.js"></script>
</body>

</html>
